<commit_before>angular.module("yds").directive("ydsWorkbenchNew", ["$ocLazyLoad", "$compile", "$templateRequest", "Data", "Basket", "Workbench", "Personalization",
    function ($ocLazyLoad, $compile, $templateRequest, Data, Basket, Workbench, Personalization) {
        return {
            restrict: "E",
            scope: {
                lang: "@",
                userId: "@"
            },
            templateUrl: Data.templatePath + "templates/workbench/workbench-new.html",
            link: function (scope, element) {
                scope.ydsAlert = "";
                var editorContainer = angular.element(element[0].querySelector(".highcharts-editor-container"));

                //if userId is undefined or empty, stop the execution of the directive
                if (_.isUndefined(scope.userId) || scope.userId.trim().length === 0) {
                    scope.ydsAlert = "The YDS component is not properly configured." +
                        "Please check the corresponding documentation section";
                    return false;
                }

                // Variable to keep the selected item in
                scope.selectedItems = [];
                scope.viewsLoaded = false;
                scope.plotOptionsLoading = false;
                scope.selection = {};
                scope.chartConfig = {};

                // Object to keep suggested templates in
                var suggestedTemplates = {
                    templates: []
                };

                var editor = null;
                var allViews = null;

                // Variable to keep last template. Default template is basic line chart.
                var lastTemplate = {
                    title: "Line chart",
                    config: {
                        "chart--type": "line"
                    }
                };

                // Check if the language attr is defined, else assign default value
                if (_.isUndefined(scope.lang) || scope.lang.trim() === "")
                    scope.lang = "en";

                // Load the required CSS & JS files for the Editor
                $ocLazyLoad.load({
                    files: [
                        Data.templatePath + "css/highcharts-editor.min.css",
                        Data.templatePath + "lib/highcharts-editor.js",
                        Data.templatePath + "lib/plugins/yds-chart-template-selector.js",
                        Data.templatePath + "lib/plugins/yds-chart-editor.js"
                    ],
                    serie: true,
                    cache: true
                }).then(function () {
                    // Start the Highcharts Editor
                    highed.ready(function () {
                        var editorOptions = {
                            features: "library view templates customize export",
                            exporter: {
                                options: "html json svg"
                            }
                        };

                        editor = highed.YDSEditor(editorContainer[0], editorOptions, suggestedTemplates, createLibraryList, createViewSelector);

                        // Add click event to the Editor's download buttons, to update the Personalization service
                        $("button.highed-imp-button > a:contains('Download')").parent().click(function () {
                            // Feed the Personalization service with a weight of 2
                            Personalization.feed(scope.userId, scope.lang, lastTemplate, scope.chartConfig.selectedView.type, 2);

                            // Feed the axis selection to the Personalization service with weight of 2
                            feedAxisToPersonalization(2);
                        });
                    });

                    // Listen for template selection event
                    editor.templateSelector.on("Select", templateSelectionHandler);
                });

                var templateSelectionHandler = function (template) {
                    // Get ID of template
                    var templateId = Data.getTemplateId(template);

                    // Save the template's ID to remember it in case the chart is exported
                    lastTemplate = templateId;

                    var concept = scope.chartConfig.selectedView.type;

                    // Send parameters to personalisation server
                    if (!_.isUndefined(concept)) {
                        Personalization.feed(scope.userId, scope.lang, templateId, concept, 1);
                    }
                };

                /**
                 * Clear the currently displayed alert.
                 */
                scope.clearAlert = function () {
                    scope.ydsAlert = "";
                };

                /**
                 * Create the view selector inside a parent element, using the template
                 * @param parent    Parent element to put view selector inside of
                 */
                var createViewSelector = function (parent) {
                    // Add class for making content scroll when it's too long to the parent
                    angular.element(parent).addClass("view-selector-step-body");

                    // Add content to the parent
                    $templateRequest(Data.templatePath + "templates/workbench/view-selector.html").then(function (html) {
                        var template = angular.element(html);

                        // Add element as a child to the parent
                        $(parent).append(template);

                        // Compile the element
                        $compile(template)(scope);
                    });
                };

                /**
                 * Create a list of the user's Library items inside a parent container
                 * @param parent    Parent element to put Library item list inside of
                 */
                var createLibraryList = function (parent) {
                    $(parent).addClass("library-list-step-container");

                    // Get basket items to show in a list
                    Basket.getBasketItems(scope.userId, "dataset")
                        .then(function (response) {
                            // Get items from response and put them in scope
                            scope.libraryItems = response.items;
                            _.map(scope.libraryItems, function (item) {
                                item.selected = false;
                                return item;
                            });

                            // Get the template which will show all the items, compile and add it ot the page
                            $templateRequest(Data.templatePath + "templates/workbench/library-list-template.html").then(function (html) {
                                var template = angular.element(html);

                                $(parent).append(template);

                                $compile(template)(scope);
                            });
                        });
                };

                /**
                 * Filter an axis object to keep only the keys needed by the API
                 * @param axis
                 */
                var getValidAxisData = function (axis) {
                    return _.pick(axis, "attribute", "field_id", "function", "label", "type");
                };

                /**
                 * Get the currently selected axes (for X and Y), and feed the personalization service with the
                 * specified weight
                 * @param weight    Weight for personalization service (integer)
                 */
                var feedAxisToPersonalization = function (weight) {
                    // Create array with IDs of axes to feed
                    var axisIds = [];

                    // Add X axis ID
                    axisIds.push(Data.getAxisId("x", scope.selection.x.field_id));

                    // Add Y axes IDs
                    var yAxisObjects = _.pluck(scope.selection.y, "selected");
                    _.each(yAxisObjects, function (axisObject) {
                        axisIds.push(Data.getAxisId("y", axisObject.field_id));
                    });

                    // Feed the axis objects with the specified weight
                    _.each(axisIds, function (axisId) {
                        Personalization.feed(undefined, scope.lang, axisId, scope.chartConfig.selectedView.type, weight);
                    });
                };

                /**
                 * Add data to the chart depending on the selection that has been made in the view/axes selection tab
                 */
                scope.createChart = function () {
                    // Get selected axes data
                    var selection = {
                        x: getValidAxisData(scope.selection.x),
                        y: _.map(scope.selection.y, function (axis) {
                            // Get only selection from axis configuration object, omitting blacklisted key
                            return getValidAxisData(axis.selected);
                        })
                    };

                    // Get chart data
                    Workbench.getLineBarVis("generic", scope.chartConfig.selectedView.type, selection.x, selection.y,
                        _.pluck(scope.selectedItems, "basket_item_id"), scope.lang, false).then(function (response) {
                        // Reset the chart preview
                        editor.chart.new();

                        // Add data to chart
                        editor.chart.data.settings(response.data);
                    }, function (error) {
                        console.error(error.message);
                    });

                    // Feed the axis selection to the Personalization service with weight of 1
                    feedAxisToPersonalization(1);
                };

                /**
                 * Transform axes to the required format, and add them to the scope.
                 * @param axes      Axes from Workbench view
                 * @param suggested (Optional) suggestions from Personalization service
                 */
                var addAxesToScope = function (axes, suggested) {
                    // Set suggested property on all axes, based on Personalisation API (random for now)
                    _.each(axes, function (axis, key) {
                        _.each(axis, function (item) {
                            item.name = item.label; // Add name, same as label (needed for angular-tree-widget)

                            // Make it suggested if the array of suggested axis items contains its ID
                            if (!_.isNull(suggested)) {
                                item.suggested = (suggested[key].indexOf(item.field_id) !== -1);
                            }
                        });
                    });

                    // Initialize/reset selected Y axes
                    scope.selection.y = [{
                        selected: "",
                        options: axes.y
                    }];

                    scope.axes = axes;
                };

                /**
                 * Update the scope object which holds the selected view, when a view is selected from the drop down
                 * @param viewType  Name of view that was selected
                 */
                scope.selectView = function (viewType) {
                    // Get the view object
                    var view = _.findWhere(allViews, {type: viewType});

                    // Get axes from the generic view object
                    var axes = _.findWhere(view.values, {
                        component: "generic"
                    });

                    // Add axes to the scope if the generic view object exists
                    if (_.has(axes, "axis-x") && _.has(axes, "axis-y")) {
                        var scopeAxes = {
                            x: axes["axis-x"],
                            y: axes["axis-y"]
                        };

                        // Get suggested axes for this concept for the Personalization API
                        Personalization.getSuggestedAxes(scope.chartConfig.selectedView.type, scopeAxes)
                            .then(function (data) {
                                addAxesToScope(scopeAxes, data);
                            }, function (error) {
                                addAxesToScope(scopeAxes, null);
                            });
                    } else {
                        scope.axes = undefined;
                    }

                    // Get suggested templates from the Personalization API
                    Personalization.getSuggestedTemplates(scope.userId, scope.chartConfig.selectedView.type)
                        .then(function (data) {
                            // Add the suggested templates in the object
                            suggestedTemplates.templates = _.map(data, Personalization.getTemplateById);

                            // Select the first category again in order to highlight the suggested templates
                            editor.templateSelector.reselectFirstCategory();
                        }, function (error) {
                            console.warn(error);

                            // Remove all suggested templates, since there was a problem
                            suggestedTemplates.templates = [];
                            editor.templateSelector.reselectFirstCategory();
                        });
                };

                /**
                 * Add a new combobox for Y axis selection
                 * @returns {boolean}
                 */
                scope.addAxisY = function () {
                    // Check if there is any combobox with default value
                    var nonSelectedCombo = _.where(scope.selection.y, {selected: ""});

                    // If there is an empty combobox or the number of comboboxes is equal with the number
                    // of line axes, stop the execution of the function
                    if (nonSelectedCombo.length > 0 || scope.selection.y.length > 5 ||
                        scope.selection.y.length === scope.axes.y.length) {
                        return false;
                    } else {
                        // Create a new combobox with default values and append it to the combobox array
                        var newCombo = {
                            selected: "",
                            options: scope.axes.y
                        };

                        scope.selection.y.push(newCombo);
                    }
                };

                /**
                 * Remove the Y axis specified by the given index
                 * @param index Index of Y axis to remove
                 */
                scope.removeAxisY = function (index) {
                    if (scope.selection.y.length > 1) {
                        scope.selection.y.splice(index, 1);
                    }
                };

                /**
                 * Filter function for the Y axis comboboxes (filters out axes that have already been selected in other
                 * comboboxes)
                 * @param index         Index of combobox to filter for
                 * @returns {Function}  Filter
                 */
                scope.yAxisComboboxFilter = function (index) {
                    return function (item) {
                        var attrSelected = false;
                        var chartAxisY = scope.selection.y;
                        var axisYConfig = _.clone(chartAxisY);

                        // If the filtered attribute is already selected, return it
                        if (!_.isNull(axisYConfig[index].selected) && axisYConfig[index].selected.attribute === item.attribute)
                            return item;

                        // Else search if the attribute is selected in one of the other compoboxes
                        axisYConfig.splice(index, 1);
                        if (axisYConfig.length > 0) {
                            var existingCombos = _.where(_.pluck(axisYConfig, "selected"), {attribute: item.attribute});

                            if (existingCombos.length > 0)
                                attrSelected = true;
                        }

                        // If the attribute is not selected in none of the comboboxes return it as available
                        if (!attrSelected)
                            return item;
                    };
                };

                /**
                 * Toggle the selected state of a Library item and update the available visualisations for the selected
                 * items
                 * @param item  Clicked item
                 */
                scope.selectItem = function (item) {
                    // Reset error that was possibly shown before
                    scope.ydsAlert = "";

                    if (item.selected === true) {
                        // Remove item from selected items
                        scope.selectedItems = _.without(scope.selectedItems, item);
                    } else {
                        // Add the item to the selected items
                        scope.selectedItems.push(item);
                    }

                    // Toggle the item's selection state
                    item.selected = !item.selected;

                    var selectedItemIds = _.pluck(scope.selectedItems, "basket_item_id");

                    // Get available views and axes for this item
                    scope.plotOptionsLoading = true;
                    Workbench.getAvailableVisualisations(scope.lang, selectedItemIds).then(function (response) {
                        // Keep view data to use for drop downs later
                        allViews = response.data;

                        // Add available views to the scope
                        scope.availableViews = _.map(response.data, function (viewItem) {
                            return {
                                label: (viewItem.label || viewItem.type),
                                type: viewItem.type
                            };
                        });
                        scope.viewsLoaded = true;
                        scope.plotOptionsLoading = false;
                    }, function (error) {
                        scope.ydsAlert = error.data.message;
                        scope.viewsLoaded = false;
                        scope.plotOptionsLoading = false;
                    });
                };
            }
        }
    }
]);
<commit_msg>Show workbench errors when creating chart<commit_after>angular.module("yds").directive("ydsWorkbenchNew", ["$ocLazyLoad", "$compile", "$templateRequest", "Data", "Basket", "Workbench", "Personalization",
    function ($ocLazyLoad, $compile, $templateRequest, Data, Basket, Workbench, Personalization) {
        return {
            restrict: "E",
            scope: {
                lang: "@",
                userId: "@"
            },
            templateUrl: Data.templatePath + "templates/workbench/workbench-new.html",
            link: function (scope, element) {
                scope.ydsAlert = "";
                var editorContainer = angular.element(element[0].querySelector(".highcharts-editor-container"));

                //if userId is undefined or empty, stop the execution of the directive
                if (_.isUndefined(scope.userId) || scope.userId.trim().length === 0) {
                    scope.ydsAlert = "The YDS component is not properly configured." +
                        "Please check the corresponding documentation section";
                    return false;
                }

                // Variable to keep the selected item in
                scope.selectedItems = [];
                scope.viewsLoaded = false;
                scope.plotOptionsLoading = false;
                scope.selection = {};
                scope.chartConfig = {};

                // Object to keep suggested templates in
                var suggestedTemplates = {
                    templates: []
                };

                var editor = null;
                var allViews = null;

                // Variable to keep last template. Default template is basic line chart.
                var lastTemplate = {
                    title: "Line chart",
                    config: {
                        "chart--type": "line"
                    }
                };

                // Check if the language attr is defined, else assign default value
                if (_.isUndefined(scope.lang) || scope.lang.trim() === "")
                    scope.lang = "en";

                // Load the required CSS & JS files for the Editor
                $ocLazyLoad.load({
                    files: [
                        Data.templatePath + "css/highcharts-editor.min.css",
                        Data.templatePath + "lib/highcharts-editor.js",
                        Data.templatePath + "lib/plugins/yds-chart-template-selector.js",
                        Data.templatePath + "lib/plugins/yds-chart-editor.js"
                    ],
                    serie: true,
                    cache: true
                }).then(function () {
                    // Start the Highcharts Editor
                    highed.ready(function () {
                        var editorOptions = {
                            features: "library view templates customize export",
                            exporter: {
                                options: "html json svg"
                            }
                        };

                        editor = highed.YDSEditor(editorContainer[0], editorOptions, suggestedTemplates, createLibraryList, createViewSelector);

                        // Add click event to the Editor's download buttons, to update the Personalization service
                        $("button.highed-imp-button > a:contains('Download')").parent().click(function () {
                            // Feed the Personalization service with a weight of 2
                            Personalization.feed(scope.userId, scope.lang, lastTemplate, scope.chartConfig.selectedView.type, 2);

                            // Feed the axis selection to the Personalization service with weight of 2
                            feedAxisToPersonalization(2);
                        });
                    });

                    // Listen for template selection event
                    editor.templateSelector.on("Select", templateSelectionHandler);
                });

                var templateSelectionHandler = function (template) {
                    // Get ID of template
                    var templateId = Data.getTemplateId(template);

                    // Save the template's ID to remember it in case the chart is exported
                    lastTemplate = templateId;

                    var concept = scope.chartConfig.selectedView.type;

                    // Send parameters to personalisation server
                    if (!_.isUndefined(concept)) {
                        Personalization.feed(scope.userId, scope.lang, templateId, concept, 1);
                    }
                };

                /**
                 * Clear the currently displayed alert.
                 */
                scope.clearAlert = function () {
                    scope.ydsAlert = "";
                };

                /**
                 * Create the view selector inside a parent element, using the template
                 * @param parent    Parent element to put view selector inside of
                 */
                var createViewSelector = function (parent) {
                    // Add class for making content scroll when it's too long to the parent
                    angular.element(parent).addClass("view-selector-step-body");

                    // Add content to the parent
                    $templateRequest(Data.templatePath + "templates/workbench/view-selector.html").then(function (html) {
                        var template = angular.element(html);

                        // Add element as a child to the parent
                        $(parent).append(template);

                        // Compile the element
                        $compile(template)(scope);
                    });
                };

                /**
                 * Create a list of the user's Library items inside a parent container
                 * @param parent    Parent element to put Library item list inside of
                 */
                var createLibraryList = function (parent) {
                    $(parent).addClass("library-list-step-container");

                    // Get basket items to show in a list
                    Basket.getBasketItems(scope.userId, "dataset")
                        .then(function (response) {
                            // Get items from response and put them in scope
                            scope.libraryItems = response.items;
                            _.map(scope.libraryItems, function (item) {
                                item.selected = false;
                                return item;
                            });

                            // Get the template which will show all the items, compile and add it ot the page
                            $templateRequest(Data.templatePath + "templates/workbench/library-list-template.html").then(function (html) {
                                var template = angular.element(html);

                                $(parent).append(template);

                                $compile(template)(scope);
                            });
                        });
                };

                /**
                 * Filter an axis object to keep only the keys needed by the API
                 * @param axis
                 */
                var getValidAxisData = function (axis) {
                    return _.pick(axis, "attribute", "field_id", "function", "label", "type");
                };

                /**
                 * Get the currently selected axes (for X and Y), and feed the personalization service with the
                 * specified weight
                 * @param weight    Weight for personalization service (integer)
                 */
                var feedAxisToPersonalization = function (weight) {
                    // Create array with IDs of axes to feed
                    var axisIds = [];

                    // Add X axis ID
                    axisIds.push(Data.getAxisId("x", scope.selection.x.field_id));

                    // Add Y axes IDs
                    var yAxisObjects = _.pluck(scope.selection.y, "selected");
                    _.each(yAxisObjects, function (axisObject) {
                        axisIds.push(Data.getAxisId("y", axisObject.field_id));
                    });

                    // Feed the axis objects with the specified weight
                    _.each(axisIds, function (axisId) {
                        Personalization.feed(undefined, scope.lang, axisId, scope.chartConfig.selectedView.type, weight);
                    });
                };

                /**
                 * Add data to the chart depending on the selection that has been made in the view/axes selection tab
                 */
                scope.createChart = function () {
                    // Clear previous error message (if any)
                    scope.ydsAlert = "";

                    // Get selected axes data
                    var selection = {
                        x: getValidAxisData(scope.selection.x),
                        y: _.map(scope.selection.y, function (axis) {
                            // Get only selection from axis configuration object, omitting blacklisted key
                            return getValidAxisData(axis.selected);
                        })
                    };

                    // Get chart data
                    Workbench.getLineBarVis("generic", scope.chartConfig.selectedView.type, selection.x, selection.y,
                        _.pluck(scope.selectedItems, "basket_item_id"), scope.lang, false).then(function (response) {
                        // Reset the chart preview
                        editor.chart.new();

                        // Add data to chart
                        editor.chart.data.settings(response.data);
                    }, function (error) {
                        scope.ydsAlert = error.data.message;
                    });

                    // Feed the axis selection to the Personalization service with weight of 1
                    feedAxisToPersonalization(1);
                };

                /**
                 * Transform axes to the required format, and add them to the scope.
                 * @param axes      Axes from Workbench view
                 * @param suggested (Optional) suggestions from Personalization service
                 */
                var addAxesToScope = function (axes, suggested) {
                    // Set suggested property on all axes, based on Personalisation API (random for now)
                    _.each(axes, function (axis, key) {
                        _.each(axis, function (item) {
                            item.name = item.label; // Add name, same as label (needed for angular-tree-widget)

                            // Make it suggested if the array of suggested axis items contains its ID
                            if (!_.isNull(suggested)) {
                                item.suggested = (suggested[key].indexOf(item.field_id) !== -1);
                            }
                        });
                    });

                    // Initialize/reset selected Y axes
                    scope.selection.y = [{
                        selected: "",
                        options: axes.y
                    }];

                    scope.axes = axes;
                };

                /**
                 * Update the scope object which holds the selected view, when a view is selected from the drop down
                 * @param viewType  Name of view that was selected
                 */
                scope.selectView = function (viewType) {
                    // Get the view object
                    var view = _.findWhere(allViews, {type: viewType});

                    // Get axes from the generic view object
                    var axes = _.findWhere(view.values, {
                        component: "generic"
                    });

                    // Add axes to the scope if the generic view object exists
                    if (_.has(axes, "axis-x") && _.has(axes, "axis-y")) {
                        var scopeAxes = {
                            x: axes["axis-x"],
                            y: axes["axis-y"]
                        };

                        // Get suggested axes for this concept for the Personalization API
                        Personalization.getSuggestedAxes(scope.chartConfig.selectedView.type, scopeAxes)
                            .then(function (data) {
                                addAxesToScope(scopeAxes, data);
                            }, function (error) {
                                addAxesToScope(scopeAxes, null);
                            });
                    } else {
                        scope.axes = undefined;
                    }

                    // Get suggested templates from the Personalization API
                    Personalization.getSuggestedTemplates(scope.userId, scope.chartConfig.selectedView.type)
                        .then(function (data) {
                            // Add the suggested templates in the object
                            suggestedTemplates.templates = _.map(data, Personalization.getTemplateById);

                            // Select the first category again in order to highlight the suggested templates
                            editor.templateSelector.reselectFirstCategory();
                        }, function (error) {
                            console.warn(error);

                            // Remove all suggested templates, since there was a problem
                            suggestedTemplates.templates = [];
                            editor.templateSelector.reselectFirstCategory();
                        });
                };

                /**
                 * Add a new combobox for Y axis selection
                 * @returns {boolean}
                 */
                scope.addAxisY = function () {
                    // Check if there is any combobox with default value
                    var nonSelectedCombo = _.where(scope.selection.y, {selected: ""});

                    // If there is an empty combobox or the number of comboboxes is equal with the number
                    // of line axes, stop the execution of the function
                    if (nonSelectedCombo.length > 0 || scope.selection.y.length > 5 ||
                        scope.selection.y.length === scope.axes.y.length) {
                        return false;
                    } else {
                        // Create a new combobox with default values and append it to the combobox array
                        var newCombo = {
                            selected: "",
                            options: scope.axes.y
                        };

                        scope.selection.y.push(newCombo);
                    }
                };

                /**
                 * Remove the Y axis specified by the given index
                 * @param index Index of Y axis to remove
                 */
                scope.removeAxisY = function (index) {
                    if (scope.selection.y.length > 1) {
                        scope.selection.y.splice(index, 1);
                    }
                };

                /**
                 * Filter function for the Y axis comboboxes (filters out axes that have already been selected in other
                 * comboboxes)
                 * @param index         Index of combobox to filter for
                 * @returns {Function}  Filter
                 */
                scope.yAxisComboboxFilter = function (index) {
                    return function (item) {
                        var attrSelected = false;
                        var chartAxisY = scope.selection.y;
                        var axisYConfig = _.clone(chartAxisY);

                        // If the filtered attribute is already selected, return it
                        if (!_.isNull(axisYConfig[index].selected) && axisYConfig[index].selected.attribute === item.attribute)
                            return item;

                        // Else search if the attribute is selected in one of the other compoboxes
                        axisYConfig.splice(index, 1);
                        if (axisYConfig.length > 0) {
                            var existingCombos = _.where(_.pluck(axisYConfig, "selected"), {attribute: item.attribute});

                            if (existingCombos.length > 0)
                                attrSelected = true;
                        }

                        // If the attribute is not selected in none of the comboboxes return it as available
                        if (!attrSelected)
                            return item;
                    };
                };

                /**
                 * Toggle the selected state of a Library item and update the available visualisations for the selected
                 * items
                 * @param item  Clicked item
                 */
                scope.selectItem = function (item) {
                    // Reset error that was possibly shown before
                    scope.ydsAlert = "";

                    if (item.selected === true) {
                        // Remove item from selected items
                        scope.selectedItems = _.without(scope.selectedItems, item);
                    } else {
                        // Add the item to the selected items
                        scope.selectedItems.push(item);
                    }

                    // Toggle the item's selection state
                    item.selected = !item.selected;

                    var selectedItemIds = _.pluck(scope.selectedItems, "basket_item_id");

                    // Get available views and axes for this item
                    scope.plotOptionsLoading = true;
                    Workbench.getAvailableVisualisations(scope.lang, selectedItemIds).then(function (response) {
                        // Keep view data to use for drop downs later
                        allViews = response.data;

                        // Add available views to the scope
                        scope.availableViews = _.map(response.data, function (viewItem) {
                            return {
                                label: (viewItem.label || viewItem.type),
                                type: viewItem.type
                            };
                        });
                        scope.viewsLoaded = true;
                        scope.plotOptionsLoading = false;
                    }, function (error) {
                        scope.ydsAlert = error.data.message;
                        scope.viewsLoaded = false;
                        scope.plotOptionsLoading = false;
                    });
                };
            }
        }
    }
]);
<|endoftext|>


<commit_before>// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

var totalTime;
var fudgeTime;
var elapsedTime;
var endTime;
var iterations;
var cycle;
var results = false;
var TIMEOUT = 15;

/**
 * Returns the value of the given property stored in the cookie.
 * @param {string} name The property name.
 * @return {string} The value of the given property, or empty string
 *     if the property was not found.
 */
function getPropertyValue(name) {
  var cookies = document.cookie.split('; ');
  for (var i = 0; i < cookies.length; ++i) {
    var t = cookies[i].split('=');
    if ((t[0] == name) && t[1])
      return t[1];
  }
  return '';
}

/**
 * Returns the value of the '__pc_timings' property.
 * @return {string} The list of all timings we got so far.
 */
function getTimings() {
  return getPropertyValue('__pc_timings');
}

/**
 * Sets the value of the '__pc_timings' property in the cookie.
 * @param {string} timings A comma-separated list of timings.
 */
function setTimings(timings) {
  document.cookie = '__pc_timings=' + timings + '; path=/';
}

/**
 * Starts the next test cycle or redirects the browser to the results page.
 */
function nextCycleOrResults() {
  // Call GC twice to cleanup JS heap before starting a new test.
  if (window.gc) {
    window.gc();
    window.gc();
  }

  var tLag = Date.now() - endTime - TIMEOUT;
  if (tLag > 0)
    fudgeTime += tLag;

  var doc;
  if (cycle == iterations) {
    document.cookie = '__pc_done=1; path=/';
    doc = '../../common/report.html';
  } else {
    doc = 'index.html';
  }

  var timings = elapsedTime;
  var oldTimings = getTimings();
  if (oldTimings != '')
    timings = oldTimings + ',' + timings;
  setTimings(timings);

  var url = doc + '?n=' + iterations + '&i=' + cycle +
      '&td=' + totalTime + '&tf=' + fudgeTime;
  document.location.href = url;
}

/**
 * Computes various running times and updates the stats reported at the end.
 * @param {!number} cycleTime The running time of the test cycle.
 */
function testComplete(cycleTime) {
  if (results)
    return;

  var oldTotalTime = 0;
  var cycleEndTime = Date.now();
  var cycleFudgeTime = 0;

  var s = document.location.search;
  if (s) {
    var params = s.substring(1).split('&');
    for (var i = 0; i < params.length; i++) {
      var f = params[i].split('=');
      switch (f[0]) {
        case 'skip':
          return;  // No calculation, just viewing
        case 'n':
          iterations = f[1];
          break;
        case 'i':
          cycle = f[1] - 0 + 1;
          break;
        case 'td':
          oldTotalTime = f[1] - 0;
          break;
        case 'tf':
          cycleFudgeTime = f[1] - 0;
          break;
      }
    }
  }
  elapsedTime = cycleTime;
  totalTime = oldTotalTime + elapsedTime;
  endTime = cycleEndTime;
  fudgeTime = cycleFudgeTime;

  setTimeout(nextCycleOrResults, TIMEOUT);
}
<commit_msg>Update database head.js to use sessionStorage.<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

var totalTime;
var fudgeTime;
var elapsedTime;
var endTime;
var iterations;
var cycle;
var results = false;
var TIMEOUT = 15;

/**
 * Returns the value of the given property stored in the cookie.
 * @param {string} name The property name.
 * @return {string} The value of the given property, or empty string
 *     if the property was not found.
 */
function getPropertyValue(name) {
  var cookies = document.cookie.split('; ');
  for (var i = 0; i < cookies.length; ++i) {
    var t = cookies[i].split('=');
    if ((t[0] == name) && t[1])
      return t[1];
  }
  return '';
}

function __get_timings() {
  if (sessionStorage == null)
    return __get_cookie("__pc_timings");
  else {
    if (sessionStorage.getItem("__pc_timings") == null)
      return "";
    else
      return sessionStorage["__pc_timings"];
  }
}
function __set_timings(timings) {
  if (sessionStorage == null)
    document.cookie = "__pc_timings=" + timings + "; path=/";
  else
    sessionStorage["__pc_timings"]=timings;
}

/**
 * Starts the next test cycle or redirects the browser to the results page.
 */
function nextCycleOrResults() {
  // Call GC twice to cleanup JS heap before starting a new test.
  if (window.gc) {
    window.gc();
    window.gc();
  }

  var tLag = Date.now() - endTime - TIMEOUT;
  if (tLag > 0)
    fudgeTime += tLag;

  var doc;
  if (cycle == iterations) {
    document.cookie = '__pc_done=1; path=/';
    doc = '../../common/report.html';
  } else {
    doc = 'index.html';
  }

  var timings = elapsedTime;
  var oldTimings = __get_timings();
  if (oldTimings != '')
    timings = oldTimings + ',' + timings;
  __set_timings(timings);

  var url = doc + '?n=' + iterations + '&i=' + cycle +
      '&td=' + totalTime + '&tf=' + fudgeTime;
  document.location.href = url;
}

/**
 * Computes various running times and updates the stats reported at the end.
 * @param {!number} cycleTime The running time of the test cycle.
 */
function testComplete(cycleTime) {
  if (results)
    return;

  var oldTotalTime = 0;
  var cycleEndTime = Date.now();
  var cycleFudgeTime = 0;

  var s = document.location.search;
  if (s) {
    var params = s.substring(1).split('&');
    for (var i = 0; i < params.length; i++) {
      var f = params[i].split('=');
      switch (f[0]) {
        case 'skip':
          return;  // No calculation, just viewing
        case 'n':
          iterations = f[1];
          break;
        case 'i':
          cycle = f[1] - 0 + 1;
          break;
        case 'td':
          oldTotalTime = f[1] - 0;
          break;
        case 'tf':
          cycleFudgeTime = f[1] - 0;
          break;
      }
    }
  }
  elapsedTime = cycleTime;
  totalTime = oldTotalTime + elapsedTime;
  endTime = cycleEndTime;
  fudgeTime = cycleFudgeTime;

  setTimeout(nextCycleOrResults, TIMEOUT);
}
<|endoftext|>


<commit_before>/**
 * @package usgin.CSW
 * @desc    usgin.CSW can interact with CSW server, parse CSW protocol and provide information for ui widiget.
 * @author  Wenwen Li <wenwen@asu.edu>
 * @author  Sheng Wu <wushengcq@gmail.com>
 * @organ   GeoDa Center for Geospatial Analysis and Computation
 *          School of Geographical Sciences and Urban Planning
 *          Arizona State University
 * @version 1.0.0
 * @license https://github.com/usgin/jsCSWwidget/blob/master/LICENSE
 * @depend  usgin.Xml, usgin.Ajax, usgin.Looger
 */

usgin.CSW = function(url, proxy) {
    this.url = url;
    this.proxy = proxy;
    this.logger = new usgin.Logger();
	this.capxml = null;
	this.xml = new usgin.Xml.getXmlParser(usgin.Util.getBrowserInfo(), {
		'csw': 'http://www.opengis.net/cat/csw/2.0.2',
		'ogc': 'http://www.opengis.net/ogc',
		'ows': 'http://www.opengis.net/ows',
		'xlink': 'http://www.w3.org/1999/xlink',
		'dc': 'http://purl.org/dc/elements/1.1/',
		'dct': 'http://purl.org/dc/terms/'
	});

	this.pageSize = 20;
}

usgin.CSW.prototype.init = function(callback) {
	var c = this;
    if(c.capxml == null) {
        var ajax = new usgin.Ajax(c.proxy, false, {
            endpoint: c.url,
            service: 'CSW',
            acceptVersions: '2.0.2',
            request: 'GetCapabilities'}).get(
            function(xml){
				c.capxml = xml;
				if(usgin.Util.isFunction(callback)) {
					callback(xml);
				}
            },
            function(msg){
                this.logger.error("get csw capabilities failed");
            }
        );
    } else {
		callback(c.capxml);
	}
}

usgin.CSW.prototype.setCapabilities = function(xml) {
	this.capxml = xml;
}

usgin.CSW.prototype.getCapabilities = function() {
	if (this.capxml == null) {
		throw new Error("CSW object not ready, please execute init() function first. from prototype");
	}
	return this.capxml;
}

usgin.CSW.prototype.setPageSize = function(size) {
	this.pageSize = size;
}

usgin.CSW.prototype.getRecords = function(literal, property, bbox, wms_filter, wfs_filter, startPosition, success, error) {
	var op = this.xml.getNodeByAttr(this.getCapabilities(),'ows:OperationsMetadata/ows:Operation','name','GetRecords');
	var params = {
		endpoint: this.url,
		service: 'CSW',
		version: this.getVersion(),
		REQUEST: op.getAttribute('name'),
		typeNames: this.getParamOpts(op, 'typeNames')[0], // csw:Record, gmd:MD_Metadata
		ElementSetName: 'full', // this.getParamOpts(op, 'ElementSetName')[0],
		resultType: this.getParamOpts(op, 'resultType')[0], // results, hits, validate
		outputFormat: this.getParamOpts(op, 'outputFormat')[0], // application/xml, text/xml
		outputSchema: this.getParamOpts(op, 'outputSchema')[0], // http://www.opengis.net/cat/csw/2.0.2, http://www.isotc211.org/2005/gmd
		maxRecords: this.pageSize,
		startPosition: (usgin.Util.validVar(startPosition)  && parseInt(startPosition) > 0)? startPosition : 1,
	};

	if (literal != null && literal.length > 0){
		params.CONSTRAINTLANGUAGE = "FILTER"; // this.getParamOpts(op, 'CONSTRAINTLANGUAGE')[0],
       	params.CONSTRAINT_LANGUAGE_VERSION = '1.1.0';
        params.Constraint = this.buildFilter(literal, property, bbox, wms_filter, wfs_filter);
	}
	var w = this;
	this.request(params, function(xml){
		var rslts = w.toJsRecords(xml);
		success(rslts);
	}, error);
}

usgin.CSW.prototype.buildFilter = function(literal, property, bbox, wms_filter, wfs_filter) {
	var b = usgin.Util.validVar(bbox) || wms_filter || wfs_filter || literal.length > 1;
	var c = "<ogc:Filter xmlns:ogc='http://www.opengis.net/ogc' xmlns:gml='http://www.opengis.net/gml'>";
	c += b ? "<ogc:And>" : "";
	c += wms_filter ? "<ogc:PropertyIsLike wildCard='%' singleChar='_' escape='\\'>"
		+ "<ogc:PropertyName>subject</ogc:PropertyName>"
		+ "<ogc:Literal>%wms%</ogc:Literal></ogc:PropertyIsLike>" : "";
	c += wfs_filter ? "<ogc:PropertyIsLike wildCard='%' singleChar='_' escape='\\'>"
		+ "<ogc:PropertyName>subject</ogc:PropertyName>"
		+ "<ogc:Literal>%wfs%</ogc:Literal></ogc:PropertyIsLike>" : "";
	for (var i=0; i<literal.length; i++) {
		c += "<ogc:PropertyIsLike wildCard='%' singleChar='_' escape='\\'>"
			+ "<ogc:PropertyName>" + (usgin.Util.validVar(property) ? property : "AnyText") + "</ogc:PropertyName>"
			+ "<ogc:Literal>" + literal[i] + "</ogc:Literal></ogc:PropertyIsLike>";
	}
	c += usgin.Util.validVar(bbox) ? "<ogc:BBOX><ogc:PropertyName>ows:BoundingBox</ogc:PropertyName><gml:Envelope>"
		+ "<gml:lowerCorner>" + bbox.minx + " " + bbox.miny + "</gml:lowerCorner>"
		+ "<gml:upperCorner>" + bbox.maxx + " " + bbox.maxy + "</gml:upperCorner>"
		+ "</gml:Envelope></ogc:BBOX>" : "";
	c += b ? "</ogc:And>" : "";
	c += "</ogc:Filter>"
	this.logger.debug(c);
	return c;
}

usgin.CSW.prototype.toJsRecords = function(xml) {
	var n = this.xml.getNodeByTag(xml, "csw:SearchResults");
	var results = {
		elementSet: n.getAttribute('elementSet'),
		nextRecord: parseInt(n.getAttribute('nextRecord')),
		numberOfRecordsMatched: parseInt(n.getAttribute('numberOfRecordsMatched')),
		numberOfRecordsReturned: parseInt(n.getAttribute('numberOfRecordsReturned')),
		records: new Array()
	}
	var rs = this.xml.getNodesByTag(n, "csw:Record");
	for(var i=0; i<rs.length; i++) {
		var r = {
			identifier: this.xml.getNodeValByTag(rs[i], "dc:identifier"),
			title: this.xml.getNodeValByTag(rs[i], 'dc:title'),
			abstract: this.xml.getNodeValByTag(rs[i], 'dct:abstract'),
			subjects: this.xml.getNodesValByTag(rs[i], 'dc:subject'),
			type: this.xml.getNodeValByTag(rs[i], 'dc:type'),
			references: this.xml.getNodesValByTag(rs[i], 'dct:references'),
			wsg84BoundingBox : this.getBoundingBox(rs[i], "ows:WGS84BoundingBox"),
			boundingBox: this.getBoundingBox(rs[i], "ows:BoundingBox"),
		}
		results.records.push(r);
	}
	return results;
}

usgin.CSW.prototype.getBoundingBox = function(rs, node) {
	var box = this.xml.getNodeByTag(rs, node);
	if (usgin.Util.validVar(box)) {
		var lower = this.xml.getNodeValByTag(box, 'ows:LowerCorner').split(" ");
		var upper = this.xml.getNodeValByTag(box, 'ows:UpperCorner').split(" ");
		return [parseFloat(lower[0]), parseFloat(lower[1]), parseFloat(upper[0]), parseFloat(upper[1])];
	} else {
		return "unknown";
	}
}

usgin.CSW.prototype.getRecordById = function(id, success, error) {
	var op = this.xml.getNodeByAttr(this.getCapabilities(), 'ows:OperationsMetadata/ows:Operation', 'name', 'GetRecordById');
	var params = {
		endpoint: this.url,
		service: 'CSW',
		version: this.getVersion(),
		REQUEST: op.getAttribute('name'),
		//ElementSetName: this.getParamOpts(op, 'ElementSetName')[0],
		ElementSetName: 'full',
		outputFormat: 'application/xml',
		Id: id
	};
	this.request(params, success, error);
}

usgin.CSW.prototype.getVersion = function() {
	var v = this.xml.getNodeByTag(this.getCapabilities(), 'ows:ServiceIdentification/ows:ServiceTypeVersion');
	return v.childNodes[0].nodeValue;
}

usgin.CSW.prototype.getParamOpts = function(op, pname) {
	var param = this.xml.getNodeByAttr(op, 'ows:Parameter', 'name', pname);
	var opts = this.xml.getNodesByTag(param, 'ows:Value');
	var rslt = [];
	for(var i=0; i<opts.length; i++) {
		rslt.push(opts[i].childNodes[0].nodeValue);
	}
	return rslt;
}

usgin.CSW.prototype.request = function(params, success, error) {
	var c = this;
	var ajax = new usgin.Ajax(this.proxy, false, params).get(function(xml){
		var ex = c.xml.getNodeByTag(xml, 'ows:Exception');
		if (!usgin.Util.validVar(ex)) {
			success(xml);
		}else{
			error(xml);
		}
	}, error);
}

<commit_msg>added wildcard to wms and wfs searches<commit_after>/**
 * @package usgin.CSW
 * @desc    usgin.CSW can interact with CSW server, parse CSW protocol and provide information for ui widiget.
 * @author  Wenwen Li <wenwen@asu.edu>
 * @author  Sheng Wu <wushengcq@gmail.com>
 * @organ   GeoDa Center for Geospatial Analysis and Computation
 *          School of Geographical Sciences and Urban Planning
 *          Arizona State University
 * @version 1.0.0
 * @license https://github.com/usgin/jsCSWwidget/blob/master/LICENSE
 * @depend  usgin.Xml, usgin.Ajax, usgin.Looger
 */

usgin.CSW = function(url, proxy) {
    this.url = url;
    this.proxy = proxy;
    this.logger = new usgin.Logger();
	this.capxml = null;
	this.xml = new usgin.Xml.getXmlParser(usgin.Util.getBrowserInfo(), {
		'csw': 'http://www.opengis.net/cat/csw/2.0.2',
		'ogc': 'http://www.opengis.net/ogc',
		'ows': 'http://www.opengis.net/ows',
		'xlink': 'http://www.w3.org/1999/xlink',
		'dc': 'http://purl.org/dc/elements/1.1/',
		'dct': 'http://purl.org/dc/terms/'
	});

	this.pageSize = 20;
}

usgin.CSW.prototype.init = function(callback) {
	var c = this;
    if(c.capxml == null) {
        var ajax = new usgin.Ajax(c.proxy, false, {
            endpoint: c.url,
            service: 'CSW',
            acceptVersions: '2.0.2',
            request: 'GetCapabilities'}).get(
            function(xml){
				c.capxml = xml;
				if(usgin.Util.isFunction(callback)) {
					callback(xml);
				}
            },
            function(msg){
                this.logger.error("get csw capabilities failed");
            }
        );
    } else {
		callback(c.capxml);
	}
}

usgin.CSW.prototype.setCapabilities = function(xml) {
	this.capxml = xml;
}

usgin.CSW.prototype.getCapabilities = function() {
	if (this.capxml == null) {
		throw new Error("CSW object not ready, please execute init() function first. from prototype");
	}
	return this.capxml;
}

usgin.CSW.prototype.setPageSize = function(size) {
	this.pageSize = size;
}

usgin.CSW.prototype.getRecords = function(literal, property, bbox, wms_filter, wfs_filter, startPosition, success, error) {
	var op = this.xml.getNodeByAttr(this.getCapabilities(),'ows:OperationsMetadata/ows:Operation','name','GetRecords');
	var params = {
		endpoint: this.url,
		service: 'CSW',
		version: this.getVersion(),
		REQUEST: op.getAttribute('name'),
		typeNames: this.getParamOpts(op, 'typeNames')[0], // csw:Record, gmd:MD_Metadata
		ElementSetName: 'full', // this.getParamOpts(op, 'ElementSetName')[0],
		resultType: this.getParamOpts(op, 'resultType')[0], // results, hits, validate
		outputFormat: this.getParamOpts(op, 'outputFormat')[0], // application/xml, text/xml
		outputSchema: this.getParamOpts(op, 'outputSchema')[0], // http://www.opengis.net/cat/csw/2.0.2, http://www.isotc211.org/2005/gmd
		maxRecords: this.pageSize,
		startPosition: (usgin.Util.validVar(startPosition)  && parseInt(startPosition) > 0)? startPosition : 1,
	};

	if (literal != null && literal.length > 0){
		params.CONSTRAINTLANGUAGE = "FILTER"; // this.getParamOpts(op, 'CONSTRAINTLANGUAGE')[0],
       	params.CONSTRAINT_LANGUAGE_VERSION = '1.1.0';
        params.Constraint = this.buildFilter(literal, property, bbox, wms_filter, wfs_filter);
	}
	var w = this;
	this.request(params, function(xml){
		var rslts = w.toJsRecords(xml);
		success(rslts);
	}, error);
}

usgin.CSW.prototype.buildFilter = function(literal, property, bbox, wms_filter, wfs_filter) {
	var b = usgin.Util.validVar(bbox) || wms_filter || wfs_filter || literal.length > 1;
	var c = "<ogc:Filter xmlns:ogc='http://www.opengis.net/ogc' xmlns:gml='http://www.opengis.net/gml'>";
	c += b ? "<ogc:And>" : "";
	c += wms_filter ? "<ogc:PropertyIsLike wildCard='%' singleChar='_' escape='\\'>"
		+ "<ogc:PropertyName>subject</ogc:PropertyName>"
		+ "<ogc:Literal>wms*</ogc:Literal></ogc:PropertyIsLike>" : "";
	c += wfs_filter ? "<ogc:PropertyIsLike wildCard='%' singleChar='_' escape='\\'>"
		+ "<ogc:PropertyName>subject</ogc:PropertyName>"
		+ "<ogc:Literal>wfs*</ogc:Literal></ogc:PropertyIsLike>" : "";
	for (var i=0; i<literal.length; i++) {
		c += "<ogc:PropertyIsLike wildCard='%' singleChar='_' escape='\\'>"
			+ "<ogc:PropertyName>" + (usgin.Util.validVar(property) ? property : "AnyText") + "</ogc:PropertyName>"
			+ "<ogc:Literal>" + literal[i] + "</ogc:Literal></ogc:PropertyIsLike>";
	}
	c += usgin.Util.validVar(bbox) ? "<ogc:BBOX><ogc:PropertyName>ows:BoundingBox</ogc:PropertyName><gml:Envelope>"
		+ "<gml:lowerCorner>" + bbox.minx + " " + bbox.miny + "</gml:lowerCorner>"
		+ "<gml:upperCorner>" + bbox.maxx + " " + bbox.maxy + "</gml:upperCorner>"
		+ "</gml:Envelope></ogc:BBOX>" : "";
	c += b ? "</ogc:And>" : "";
	c += "</ogc:Filter>"
	this.logger.debug(c);
	return c;
}

usgin.CSW.prototype.toJsRecords = function(xml) {
	var n = this.xml.getNodeByTag(xml, "csw:SearchResults");
	var results = {
		elementSet: n.getAttribute('elementSet'),
		nextRecord: parseInt(n.getAttribute('nextRecord')),
		numberOfRecordsMatched: parseInt(n.getAttribute('numberOfRecordsMatched')),
		numberOfRecordsReturned: parseInt(n.getAttribute('numberOfRecordsReturned')),
		records: new Array()
	}
	var rs = this.xml.getNodesByTag(n, "csw:Record");
	for(var i=0; i<rs.length; i++) {
		var r = {
			identifier: this.xml.getNodeValByTag(rs[i], "dc:identifier"),
			title: this.xml.getNodeValByTag(rs[i], 'dc:title'),
			abstract: this.xml.getNodeValByTag(rs[i], 'dct:abstract'),
			subjects: this.xml.getNodesValByTag(rs[i], 'dc:subject'),
			type: this.xml.getNodeValByTag(rs[i], 'dc:type'),
			references: this.xml.getNodesValByTag(rs[i], 'dct:references'),
			wsg84BoundingBox : this.getBoundingBox(rs[i], "ows:WGS84BoundingBox"),
			boundingBox: this.getBoundingBox(rs[i], "ows:BoundingBox"),
		}
		results.records.push(r);
	}
	return results;
}

usgin.CSW.prototype.getBoundingBox = function(rs, node) {
	var box = this.xml.getNodeByTag(rs, node);
	if (usgin.Util.validVar(box)) {
		var lower = this.xml.getNodeValByTag(box, 'ows:LowerCorner').split(" ");
		var upper = this.xml.getNodeValByTag(box, 'ows:UpperCorner').split(" ");
		return [parseFloat(lower[0]), parseFloat(lower[1]), parseFloat(upper[0]), parseFloat(upper[1])];
	} else {
		return "unknown";
	}
}

usgin.CSW.prototype.getRecordById = function(id, success, error) {
	var op = this.xml.getNodeByAttr(this.getCapabilities(), 'ows:OperationsMetadata/ows:Operation', 'name', 'GetRecordById');
	var params = {
		endpoint: this.url,
		service: 'CSW',
		version: this.getVersion(),
		REQUEST: op.getAttribute('name'),
		//ElementSetName: this.getParamOpts(op, 'ElementSetName')[0],
		ElementSetName: 'full',
		outputFormat: 'application/xml',
		Id: id
	};
	this.request(params, success, error);
}

usgin.CSW.prototype.getVersion = function() {
	var v = this.xml.getNodeByTag(this.getCapabilities(), 'ows:ServiceIdentification/ows:ServiceTypeVersion');
	return v.childNodes[0].nodeValue;
}

usgin.CSW.prototype.getParamOpts = function(op, pname) {
	var param = this.xml.getNodeByAttr(op, 'ows:Parameter', 'name', pname);
	var opts = this.xml.getNodesByTag(param, 'ows:Value');
	var rslt = [];
	for(var i=0; i<opts.length; i++) {
		rslt.push(opts[i].childNodes[0].nodeValue);
	}
	return rslt;
}

usgin.CSW.prototype.request = function(params, success, error) {
	var c = this;
	var ajax = new usgin.Ajax(this.proxy, false, params).get(function(xml){
		var ex = c.xml.getNodeByTag(xml, 'ows:Exception');
		if (!usgin.Util.validVar(ex)) {
			success(xml);
		}else{
			error(xml);
		}
	}, error);
}

<|endoftext|>


<commit_before>'use strict';
module.exports = clean

var EventEmitter = require('events').EventEmitter
var forwardEvents = require('../lib/forward-events')
var readGraph = require('./read-graph')
var common = require('./common')
var util = require('util')
var fs = require('fs')
var extractCliRefs = require('./extract-cli-refs')

var DRY_REM = 'Would remove: %s'
var REM = 'Removing: %s'

function clean(opts) {
    var ev = new EventEmitter()
    var rg = readGraph(opts.file, common.LOG_PATH, opts.argv.remain)
    forwardEvents(ev, rg, function graphRead(errored, data) {
        if (errored) return ev.emit('finish')
        var ecr = extractCliRefs(data.graph, data.cliRefs)
        forwardEvents(ev, ecr, function refExtracted(errored, files) {
            if (errored) return ev.emit('finish')
            files = cleanSort(files, function (file) {
                return data.log.isGenerated(file.path)
            })
            forwardEvents(ev, cleanFiles(data, files, opts))
        })
    })
    return ev
}

function cleanFiles(data, files, opts) {
    var ev = new EventEmitter()
    if (files.length === 0) {
        if (!opts.robot) console.log('Nothing to clean.')
        return process.nextTick(ev.emit.bind(ev, 'finish'))
    }
    var unlink = opts['dry-run'] ? dryUnlink : fs.unlink
    var msgTpl = opts['dry-run'] ? DRY_REM : REM
    ;(function next(i) {
        if (i === files.length) return ev.emit('finish')
        if (!opts.robot)
            console.log(util.format(msgTpl, files[i].path))
        unlink(files[i].path, function (err) {
            if (err) {
                ev.emit('error', err)
                return next(i + 1)
            }
            data.log.forget(files[i].path)
            return next(i + 1)
        })
    })(0)
    return ev
}

function dryUnlink(filePath, cb) {
    setImmediate(cb.bind(null, null))
}

function cleanSort(targets, iter) {
    var st = {marks: {}, stack: [], list: [], iter: iter}
    for (var i = 0; i < targets.length; ++i)
        cleanVisit(st, targets[i])
    return st.list
}

function cleanVisit(st, target) {
    var marks = st.marks
    if (marks.hasOwnProperty(target.path)) {
        if (!marks[target.path].visiting) return
        throw new Error('cycle errors should not happen here')
    }
    var mark = marks[target.path] = {
        file: target, visiting: true, index: st.stack.length
    }
    st.stack.push(target)
    target.outEdges.forEach(function (outEdge) {
        outEdge.outFiles.forEach(function (outFile) {
            cleanVisit(st, outFile)
        })
    })
    st.stack.pop()
    if (st.iter(target)) st.list.push(target)
    mark.visiting = false
}
<commit_msg>Save log after clean + proper robot output<commit_after>'use strict';
module.exports = clean

var EventEmitter = require('events').EventEmitter
var forwardEvents = require('../lib/forward-events')
var readGraph = require('./read-graph')
var common = require('./common')
var util = require('util')
var fs = require('fs')
var extractCliRefs = require('./extract-cli-refs')
var mkdirp = require('mkdirp')
var helpers = require('./helpers')
var path = require('path')

var DRY_REM = 'Would remove: %s'
var REM = 'Removing: %s'

function clean(opts) {
    var ev = new EventEmitter()
    var rg = readGraph(opts.file, common.LOG_PATH, opts.argv.remain)
    forwardEvents(ev, rg, function graphRead(errored, data) {
        if (errored) return ev.emit('finish')
        var ecr = extractCliRefs(data.graph, data.cliRefs)
        forwardEvents(ev, ecr, function refExtracted(errored, files) {
            if (errored) return ev.emit('finish')
            files = cleanSort(files, function (file) {
                return data.log.isGenerated(file.path)
            })
            var cf = cleanFiles(data, files, opts)
            forwardEvents(ev, cf, function cleaned() {
                if (opts['dry-run']) return ev.emit('finish')
                mkdirp(path.dirname(common.LOG_PATH), function (err) {
                    if (err) return helpers.bailoutEv(ev, err)
                    var s = data.log.save(fs.createWriteStream(common.LOG_PATH))
                    s.end(function () {
                        ev.emit('finish')
                    })
                })
            })
        })
    })
    return ev
}

function cleanFiles(data, files, opts) {
    var ev = new EventEmitter()
    if (files.length === 0)
        return alreadyClean(ev, data, opts)
    var unlink = opts['dry-run'] ? dryUnlink : fs.unlink
    var msgTpl = opts['dry-run'] ? DRY_REM : REM
    if (opts.robot) msgTpl = opts['dry-run'] ? 'wr %s' : ' r %s'
    ;(function next(i) {
        if (i === files.length) {
            if (opts['robot']) console.log(' D')
            else console.log('Done.')
            return ev.emit('finish')
        }
        console.log(util.format(msgTpl, files[i].path))
        unlink(files[i].path, function (err) {
            if (err) {
                ev.emit('error', err)
                return next(i + 1)
            }
            data.log.forget(files[i].path)
            return next(i + 1)
        })
    })(0)
    return ev
}

function alreadyClean(ev, data, opts) {
    if (opts['robot']) {
        console.log(' D')
    } else {
        if (data.cliRefs.length === 0) {
            console.log('Nothing to clean.')
        } else {
            var list = data.cliRefs.map(function (ref) {
                return ref.value
            }).join(', ')
            console.log(util.format('Those are clean: %s', list))
        }
    }
    process.nextTick(ev.emit.bind(ev, 'finish'))
    return ev
}

function dryUnlink(filePath, cb) {
    setImmediate(cb.bind(null, null))
}

function cleanSort(targets, iter) {
    var st = {marks: {}, stack: [], list: [], iter: iter}
    for (var i = 0; i < targets.length; ++i)
        cleanVisit(st, targets[i])
    return st.list
}

function cleanVisit(st, target) {
    var marks = st.marks
    if (marks.hasOwnProperty(target.path)) {
        if (!marks[target.path].visiting) return
        throw new Error('cycle errors should not happen here')
    }
    var mark = marks[target.path] = {
        file: target, visiting: true, index: st.stack.length
    }
    st.stack.push(target)
    target.outEdges.forEach(function (outEdge) {
        outEdge.outFiles.forEach(function (outFile) {
            cleanVisit(st, outFile)
        })
    })
    st.stack.pop()
    if (st.iter(target)) st.list.push(target)
    mark.visiting = false
}
<|endoftext|>


<commit_before>/**
 * @fileOverview Convert JSHint's results to a jslint_xml-compatible format
 * @see https://github.com/jshint/jshint/blob/master/src/reporters/jslint_xml.js
 */
'use strict';

exports.getHeader = function () {
    var out = [];
    out.push('<?xml version="1.0" encoding="utf-8"?>');
    out.push('<jslint>');
    return out.join('\n');
};

exports.getFooter = function () {
    return '\n</jslint>\n';
};

/**
 * @param    {Array}    results
 * @return {String} XML output
 */
exports.formatContent = function (results) {
    var files = {},
    out = [],
    pairs = {
        '&': '&',
        '"': '"',
        '\'': ''',
        '<': '<',
        '>': '>'
    },
    file, i, issue;

    function encode(s) {
        for (var r in pairs) {
            if (typeof s !== 'undefined') {
                s = s.replace(new RegExp(r, 'g'), pairs[r]);
            }
        }
        return s || '';
    }

    results.forEach(function (result) {
        result.file = result.file.replace(/^\.\//, '');
        if (!files[result.file]) {
            files[result.file] = [];
        }
        files[result.file].push(result.error);
    });

    for (file in files) {
        out.push('\t<file name="' + file + '">');
        for (i = 0; i < files[file].length; i++) {
            issue = files[file][i];
            out.push('\t\t<issue line="' + issue.line +
                '" char="' + issue.character +
                '" reason="' + encode(issue.reason) +
                '" evidence="' + encode(issue.evidence) +
                (issue.code ? '" severity="' + encode(issue.code.charAt(0)) : '') +
                '" />');
        }
        out.push('\t</file>');
    }

    return out.join('\n');
};
<commit_msg>Added a fix for the jslint_xml emitter - now has a line break after the first <jslint> tag<commit_after>/**
 * @fileOverview Convert JSHint's results to a jslint_xml-compatible format
 * @see https://github.com/jshint/jshint/blob/master/src/reporters/jslint_xml.js
 */
'use strict';

exports.getHeader = function () {
    var out = [];
    out.push('<?xml version="1.0" encoding="utf-8"?>');
    out.push('<jslint>\n');
    return out.join('\n');
};

exports.getFooter = function () {
    return '\n</jslint>\n';
};

/**
 * @param    {Array}    results
 * @return {String} XML output
 */
exports.formatContent = function (results) {
    var files = {},
    out = [],
    pairs = {
        '&': '&',
        '"': '"',
        '\'': ''',
        '<': '<',
        '>': '>'
    },
    file, i, issue;

    function encode(s) {
        for (var r in pairs) {
            if (typeof s !== 'undefined') {
                s = s.replace(new RegExp(r, 'g'), pairs[r]);
            }
        }
        return s || '';
    }

    results.forEach(function (result) {
        result.file = result.file.replace(/^\.\//, '');
        if (!files[result.file]) {
            files[result.file] = [];
        }
        files[result.file].push(result.error);
    });

    for (file in files) {
        out.push('\t<file name="' + file + '">');
        for (i = 0; i < files[file].length; i++) {
            issue = files[file][i];
            out.push('\t\t<issue line="' + issue.line +
                '" char="' + issue.character +
                '" reason="' + encode(issue.reason) +
                '" evidence="' + encode(issue.evidence) +
                (issue.code ? '" severity="' + encode(issue.code.charAt(0)) : '') +
                '" />');
        }
        out.push('\t</file>');
    }

    return out.join('\n');
};
<|endoftext|>


<commit_before>import Bresenham from './bresenham';
import ImageDebug from '../common/image_debug.ts';
import Code128Reader from '../reader/code_128_reader';
import EANReader from '../reader/ean_reader';
import Code39Reader from '../reader/code_39_reader';
import Code39VINReader from '../reader/code_39_vin_reader';
import CodabarReader from '../reader/codabar_reader';
import UPCReader from '../reader/upc_reader';
import EAN8Reader from '../reader/ean_8_reader';
import EAN2Reader from '../reader/ean_2_reader';
import EAN5Reader from '../reader/ean_5_reader';
import UPCEReader from '../reader/upc_e_reader';
import I2of5Reader from '../reader/i2of5_reader';
import TwoOfFiveReader from '../reader/2of5_reader';
import Code93Reader from '../reader/code_93_reader';

const READERS = {
    code_128_reader: Code128Reader,
    ean_reader: EANReader,
    ean_5_reader: EAN5Reader,
    ean_2_reader: EAN2Reader,
    ean_8_reader: EAN8Reader,
    code_39_reader: Code39Reader,
    code_39_vin_reader: Code39VINReader,
    codabar_reader: CodabarReader,
    upc_reader: UPCReader,
    upc_e_reader: UPCEReader,
    i2of5_reader: I2of5Reader,
    '2of5_reader': TwoOfFiveReader,
    code_93_reader: Code93Reader,
};

export default {
    registerReader: (name, reader) => {
        READERS[name] = reader;
    },
    create: function(config, inputImageWrapper) {
        var _canvas = {
                ctx: {
                    frequency: null,
                    pattern: null,
                    overlay: null,
                },
                dom: {
                    frequency: null,
                    pattern: null,
                    overlay: null,
                },
            },
            _barcodeReaders = [];

        initCanvas();
        initReaders();
        initConfig();

        function initCanvas() {
            if (ENV.development && typeof document !== 'undefined') {
                var $debug = document.querySelector('#debug.detection');
                _canvas.dom.frequency = document.querySelector('canvas.frequency');
                if (!_canvas.dom.frequency) {
                    _canvas.dom.frequency = document.createElement('canvas');
                    _canvas.dom.frequency.className = 'frequency';
                    if ($debug) {
                        $debug.appendChild(_canvas.dom.frequency);
                    }
                }
                _canvas.ctx.frequency = _canvas.dom.frequency.getContext('2d');

                _canvas.dom.pattern = document.querySelector('canvas.patternBuffer');
                if (!_canvas.dom.pattern) {
                    _canvas.dom.pattern = document.createElement('canvas');
                    _canvas.dom.pattern.className = 'patternBuffer';
                    if ($debug) {
                        $debug.appendChild(_canvas.dom.pattern);
                    }
                }
                _canvas.ctx.pattern = _canvas.dom.pattern.getContext('2d');

                _canvas.dom.overlay = document.querySelector('canvas.drawingBuffer');
                if (_canvas.dom.overlay) {
                    _canvas.ctx.overlay = _canvas.dom.overlay.getContext('2d');
                }
            }
        }

        function initReaders() {
            config.readers.forEach(function(readerConfig) {
                var reader,
                    configuration = {},
                    supplements = [];

                if (typeof readerConfig === 'object') {
                    reader = readerConfig.format;
                    configuration = readerConfig.config;
                } else if (typeof readerConfig === 'string') {
                    reader = readerConfig;
                }
                if (ENV.development) {
                    console.log('Before registering reader: ', reader);
                }
                if (configuration.supplements) {
                    supplements = configuration
                        .supplements.map((supplement) => {
                            return new READERS[supplement]();
                        });
                }
                try {
                    const readerObj = new READERS[reader](configuration, supplements);
                    _barcodeReaders.push(readerObj);
                } catch (err) {
                    console.error('* Error constructing reader ', reader, err);
                    throw err;
                }
            });
            if (ENV.development) {
                console.log('Registered Readers: ' + _barcodeReaders
                    .map((reader) => JSON.stringify({format: reader.FORMAT, config: reader.config}))
                    .join(', '));
            }
        }

        function initConfig() {
            if (ENV.development && typeof document !== 'undefined') {
                var i,
                    vis = [{
                        node: _canvas.dom.frequency,
                        prop: config.debug.showFrequency,
                    }, {
                        node: _canvas.dom.pattern,
                        prop: config.debug.showPattern,
                    }];

                for (i = 0; i < vis.length; i++) {
                    if (vis[i].prop === true) {
                        vis[i].node.style.display = 'block';
                    } else {
                        vis[i].node.style.display = 'none';
                    }
                }
            }
        }

        /**
         * extend the line on both ends
         * @param {Array} line
         * @param {Number} angle
         */
        function getExtendedLine(line, angle, ext) {
            function extendLine(amount) {
                var extension = {
                    y: amount * Math.sin(angle),
                    x: amount * Math.cos(angle),
                };

                line[0].y -= extension.y;
                line[0].x -= extension.x;
                line[1].y += extension.y;
                line[1].x += extension.x;
            }

            // check if inside image
            extendLine(ext);
            while (ext > 1 && (!inputImageWrapper.inImageWithBorder(line[0], 0)
                    || !inputImageWrapper.inImageWithBorder(line[1], 0))) {
                ext -= Math.ceil(ext / 2);
                extendLine(-ext);
            }
            return line;
        }

        function getLine(box) {
            return [{
                x: (box[1][0] - box[0][0]) / 2 + box[0][0],
                y: (box[1][1] - box[0][1]) / 2 + box[0][1],
            }, {
                x: (box[3][0] - box[2][0]) / 2 + box[2][0],
                y: (box[3][1] - box[2][1]) / 2 + box[2][1],
            }];
        }

        function tryDecode(line) {
            var result = null,
                i,
                barcodeLine = Bresenham.getBarcodeLine(inputImageWrapper, line[0], line[1]);

            if (ENV.development && config.debug.showFrequency) {
                ImageDebug.drawPath(line, {x: 'x', y: 'y'}, _canvas.ctx.overlay, {color: 'red', lineWidth: 3});
                Bresenham.debug.printFrequency(barcodeLine.line, _canvas.dom.frequency);
            }

            Bresenham.toBinaryLine(barcodeLine);

            if (ENV.development && config.debug.showPattern) {
                Bresenham.debug.printPattern(barcodeLine.line, _canvas.dom.pattern);
            }

            for ( i = 0; i < _barcodeReaders.length && result === null; i++) {
                result = _barcodeReaders[i].decodePattern(barcodeLine.line);
            }
            if (result === null){
                return null;
            }
            return {
                codeResult: result,
                barcodeLine: barcodeLine,
            };
        }

        /**
         * This method slices the given area apart and tries to detect a barcode-pattern
         * for each slice. It returns the decoded barcode, or null if nothing was found
         * @param {Array} box
         * @param {Array} line
         * @param {Number} lineAngle
         */
        function tryDecodeBruteForce(box, line, lineAngle) {
            var sideLength = Math.sqrt(Math.pow(box[1][0] - box[0][0], 2) + Math.pow((box[1][1] - box[0][1]), 2)),
                i,
                slices = 16,
                result = null,
                dir,
                extension,
                xdir = Math.sin(lineAngle),
                ydir = Math.cos(lineAngle);

            for ( i = 1; i < slices && result === null; i++) {
                // move line perpendicular to angle
                dir = sideLength / slices * i * (i % 2 === 0 ? -1 : 1);
                extension = {
                    y: dir * xdir,
                    x: dir * ydir,
                };
                line[0].y += extension.x;
                line[0].x -= extension.y;
                line[1].y += extension.x;
                line[1].x -= extension.y;

                result = tryDecode(line);
            }
            return result;
        }

        function getLineLength(line) {
            return Math.sqrt(
                Math.pow(Math.abs(line[1].y - line[0].y), 2) +
                Math.pow(Math.abs(line[1].x - line[0].x), 2));
        }

        function decodeFromImage(imageWrapper) {
            let result = null;
            for (let i = 0; i < _barcodeReaders.length && result === null; i++) {
                result = _barcodeReaders[i].decodeImage ? _barcodeReaders[i].decodeImage(imageWrapper) : null;
            }
            return result;
        }
        /**
         * With the help of the configured readers (Code128 or EAN) this function tries to detect a
         * valid barcode pattern within the given area.
         * @param {Object} box The area to search in
         * @returns {Object} the result {codeResult, line, angle, pattern, threshold}
         */
        function decodeFromBoundingBox(box) {
            var line,
                lineAngle,
                ctx = _canvas.ctx.overlay,
                result,
                lineLength;

            if (ENV.development) {
                if (config.debug.drawBoundingBox && ctx) {
                    ImageDebug.drawPath(box, {x: 0, y: 1}, ctx, {color: 'blue', lineWidth: 2});
                }
            }

            line = getLine(box);
            lineLength = getLineLength(line);
            lineAngle = Math.atan2(line[1].y - line[0].y, line[1].x - line[0].x);
            line = getExtendedLine(line, lineAngle, Math.floor(lineLength * 0.1));
            if (line === null){
                return null;
            }

            result = tryDecode(line);
            if (result === null) {
                result = tryDecodeBruteForce(box, line, lineAngle);
            }

            if (result === null) {
                return null;
            }

            if (ENV.development && result && config.debug.drawScanline && ctx) {
                ImageDebug.drawPath(line, {x: 'x', y: 'y'}, ctx, {color: 'red', lineWidth: 3});
            }

            return {
                codeResult: result.codeResult,
                line: line,
                angle: lineAngle,
                pattern: result.barcodeLine.line,
                threshold: result.barcodeLine.threshold,
            };
        }

        return {
            decodeFromBoundingBox: function(box) {
                return decodeFromBoundingBox(box);
            },
            decodeFromBoundingBoxes: function(boxes) {
                var i, result,
                    barcodes = [],
                    multiple = config.multiple;

                for ( i = 0; i < boxes.length; i++) {
                    const box = boxes[i];
                    result = decodeFromBoundingBox(box) || {};
                    result.box = box;

                    if (multiple) {
                        barcodes.push(result);
                    } else if (result.codeResult) {
                        return result;
                    }
                }

                if (multiple) {
                    return {
                        barcodes,
                    };
                }
            },
            decodeFromImage: function(inputImageWrapper) {
                const result = decodeFromImage(inputImageWrapper);
                return result;
            },
            registerReader: function(name, reader) {
                if (READERS[name]) {
                    throw new Error('cannot register existing reader', name);
                }
                READERS[name] = reader;
            },
            setReaders: function(readers) {
                config.readers = readers;
                _barcodeReaders.length = 0;
                initReaders();
            },
        };
    },
};
<commit_msg>add Code 32<commit_after>import Bresenham from './bresenham';
import ImageDebug from '../common/image_debug.ts';
import Code128Reader from '../reader/code_128_reader';
import EANReader from '../reader/ean_reader';
import Code39Reader from '../reader/code_39_reader';
import Code39VINReader from '../reader/code_39_vin_reader';
import CodabarReader from '../reader/codabar_reader';
import UPCReader from '../reader/upc_reader';
import EAN8Reader from '../reader/ean_8_reader';
import EAN2Reader from '../reader/ean_2_reader';
import EAN5Reader from '../reader/ean_5_reader';
import UPCEReader from '../reader/upc_e_reader';
import I2of5Reader from '../reader/i2of5_reader';
import TwoOfFiveReader from '../reader/2of5_reader';
import Code93Reader from '../reader/code_93_reader';
import Code32Reader from '../reader/code_32_reader';

const READERS = {
    code_128_reader: Code128Reader,
    ean_reader: EANReader,
    ean_5_reader: EAN5Reader,
    ean_2_reader: EAN2Reader,
    ean_8_reader: EAN8Reader,
    code_39_reader: Code39Reader,
    code_39_vin_reader: Code39VINReader,
    codabar_reader: CodabarReader,
    upc_reader: UPCReader,
    upc_e_reader: UPCEReader,
    i2of5_reader: I2of5Reader,
    '2of5_reader': TwoOfFiveReader,
    code_93_reader: Code93Reader,
};

export default {
    registerReader: (name, reader) => {
        READERS[name] = reader;
    },
    create: function(config, inputImageWrapper) {
        var _canvas = {
                ctx: {
                    frequency: null,
                    pattern: null,
                    overlay: null,
                },
                dom: {
                    frequency: null,
                    pattern: null,
                    overlay: null,
                },
            },
            _barcodeReaders = [];

        initCanvas();
        initReaders();
        initConfig();

        function initCanvas() {
            if (ENV.development && typeof document !== 'undefined') {
                var $debug = document.querySelector('#debug.detection');
                _canvas.dom.frequency = document.querySelector('canvas.frequency');
                if (!_canvas.dom.frequency) {
                    _canvas.dom.frequency = document.createElement('canvas');
                    _canvas.dom.frequency.className = 'frequency';
                    if ($debug) {
                        $debug.appendChild(_canvas.dom.frequency);
                    }
                }
                _canvas.ctx.frequency = _canvas.dom.frequency.getContext('2d');

                _canvas.dom.pattern = document.querySelector('canvas.patternBuffer');
                if (!_canvas.dom.pattern) {
                    _canvas.dom.pattern = document.createElement('canvas');
                    _canvas.dom.pattern.className = 'patternBuffer';
                    if ($debug) {
                        $debug.appendChild(_canvas.dom.pattern);
                    }
                }
                _canvas.ctx.pattern = _canvas.dom.pattern.getContext('2d');

                _canvas.dom.overlay = document.querySelector('canvas.drawingBuffer');
                if (_canvas.dom.overlay) {
                    _canvas.ctx.overlay = _canvas.dom.overlay.getContext('2d');
                }
            }
        }

        function initReaders() {
            config.readers.forEach(function(readerConfig) {
                var reader,
                    configuration = {},
                    supplements = [];

                if (typeof readerConfig === 'object') {
                    reader = readerConfig.format;
                    configuration = readerConfig.config;
                } else if (typeof readerConfig === 'string') {
                    reader = readerConfig;
                }
                if (ENV.development) {
                    console.log('Before registering reader: ', reader);
                }
                if (configuration.supplements) {
                    supplements = configuration
                        .supplements.map((supplement) => {
                            return new READERS[supplement]();
                        });
                }
                try {
                    const readerObj = new READERS[reader](configuration, supplements);
                    _barcodeReaders.push(readerObj);
                } catch (err) {
                    console.error('* Error constructing reader ', reader, err);
                    throw err;
                }
            });
            if (ENV.development) {
                console.log('Registered Readers: ' + _barcodeReaders
                    .map((reader) => JSON.stringify({format: reader.FORMAT, config: reader.config}))
                    .join(', '));
            }
        }

        function initConfig() {
            if (ENV.development && typeof document !== 'undefined') {
                var i,
                    vis = [{
                        node: _canvas.dom.frequency,
                        prop: config.debug.showFrequency,
                    }, {
                        node: _canvas.dom.pattern,
                        prop: config.debug.showPattern,
                    }];

                for (i = 0; i < vis.length; i++) {
                    if (vis[i].prop === true) {
                        vis[i].node.style.display = 'block';
                    } else {
                        vis[i].node.style.display = 'none';
                    }
                }
            }
        }

        /**
         * extend the line on both ends
         * @param {Array} line
         * @param {Number} angle
         */
        function getExtendedLine(line, angle, ext) {
            function extendLine(amount) {
                var extension = {
                    y: amount * Math.sin(angle),
                    x: amount * Math.cos(angle),
                };

                line[0].y -= extension.y;
                line[0].x -= extension.x;
                line[1].y += extension.y;
                line[1].x += extension.x;
            }

            // check if inside image
            extendLine(ext);
            while (ext > 1 && (!inputImageWrapper.inImageWithBorder(line[0], 0)
                    || !inputImageWrapper.inImageWithBorder(line[1], 0))) {
                ext -= Math.ceil(ext / 2);
                extendLine(-ext);
            }
            return line;
        }

        function getLine(box) {
            return [{
                x: (box[1][0] - box[0][0]) / 2 + box[0][0],
                y: (box[1][1] - box[0][1]) / 2 + box[0][1],
            }, {
                x: (box[3][0] - box[2][0]) / 2 + box[2][0],
                y: (box[3][1] - box[2][1]) / 2 + box[2][1],
            }];
        }

        function tryDecode(line) {
            var result = null,
                i,
                barcodeLine = Bresenham.getBarcodeLine(inputImageWrapper, line[0], line[1]);

            if (ENV.development && config.debug.showFrequency) {
                ImageDebug.drawPath(line, {x: 'x', y: 'y'}, _canvas.ctx.overlay, {color: 'red', lineWidth: 3});
                Bresenham.debug.printFrequency(barcodeLine.line, _canvas.dom.frequency);
            }

            Bresenham.toBinaryLine(barcodeLine);

            if (ENV.development && config.debug.showPattern) {
                Bresenham.debug.printPattern(barcodeLine.line, _canvas.dom.pattern);
            }

            for ( i = 0; i < _barcodeReaders.length && result === null; i++) {
                result = _barcodeReaders[i].decodePattern(barcodeLine.line);
            }
            if (result === null){
                return null;
            }
            return {
                codeResult: result,
                barcodeLine: barcodeLine,
            };
        }

        /**
         * This method slices the given area apart and tries to detect a barcode-pattern
         * for each slice. It returns the decoded barcode, or null if nothing was found
         * @param {Array} box
         * @param {Array} line
         * @param {Number} lineAngle
         */
        function tryDecodeBruteForce(box, line, lineAngle) {
            var sideLength = Math.sqrt(Math.pow(box[1][0] - box[0][0], 2) + Math.pow((box[1][1] - box[0][1]), 2)),
                i,
                slices = 16,
                result = null,
                dir,
                extension,
                xdir = Math.sin(lineAngle),
                ydir = Math.cos(lineAngle);

            for ( i = 1; i < slices && result === null; i++) {
                // move line perpendicular to angle
                dir = sideLength / slices * i * (i % 2 === 0 ? -1 : 1);
                extension = {
                    y: dir * xdir,
                    x: dir * ydir,
                };
                line[0].y += extension.x;
                line[0].x -= extension.y;
                line[1].y += extension.x;
                line[1].x -= extension.y;

                result = tryDecode(line);
            }
            return result;
        }

        function getLineLength(line) {
            return Math.sqrt(
                Math.pow(Math.abs(line[1].y - line[0].y), 2) +
                Math.pow(Math.abs(line[1].x - line[0].x), 2));
        }

        function decodeFromImage(imageWrapper) {
            let result = null;
            for (let i = 0; i < _barcodeReaders.length && result === null; i++) {
                result = _barcodeReaders[i].decodeImage ? _barcodeReaders[i].decodeImage(imageWrapper) : null;
            }
            return result;
        }
        /**
         * With the help of the configured readers (Code128 or EAN) this function tries to detect a
         * valid barcode pattern within the given area.
         * @param {Object} box The area to search in
         * @returns {Object} the result {codeResult, line, angle, pattern, threshold}
         */
        function decodeFromBoundingBox(box) {
            var line,
                lineAngle,
                ctx = _canvas.ctx.overlay,
                result,
                lineLength;

            if (ENV.development) {
                if (config.debug.drawBoundingBox && ctx) {
                    ImageDebug.drawPath(box, {x: 0, y: 1}, ctx, {color: 'blue', lineWidth: 2});
                }
            }

            line = getLine(box);
            lineLength = getLineLength(line);
            lineAngle = Math.atan2(line[1].y - line[0].y, line[1].x - line[0].x);
            line = getExtendedLine(line, lineAngle, Math.floor(lineLength * 0.1));
            if (line === null){
                return null;
            }

            result = tryDecode(line);
            if (result === null) {
                result = tryDecodeBruteForce(box, line, lineAngle);
            }

            if (result === null) {
                return null;
            }

            if (ENV.development && result && config.debug.drawScanline && ctx) {
                ImageDebug.drawPath(line, {x: 'x', y: 'y'}, ctx, {color: 'red', lineWidth: 3});
            }

            return {
                codeResult: result.codeResult,
                line: line,
                angle: lineAngle,
                pattern: result.barcodeLine.line,
                threshold: result.barcodeLine.threshold,
            };
        }

        return {
            decodeFromBoundingBox: function(box) {
                return decodeFromBoundingBox(box);
            },
            decodeFromBoundingBoxes: function(boxes) {
                var i, result,
                    barcodes = [],
                    multiple = config.multiple;

                for ( i = 0; i < boxes.length; i++) {
                    const box = boxes[i];
                    result = decodeFromBoundingBox(box) || {};
                    result.box = box;

                    if (multiple) {
                        barcodes.push(result);
                    } else if (result.codeResult) {
                        return result;
                    }
                }

                if (multiple) {
                    return {
                        barcodes,
                    };
                }
            },
            decodeFromImage: function(inputImageWrapper) {
                const result = decodeFromImage(inputImageWrapper);
                return result;
            },
            registerReader: function(name, reader) {
                if (READERS[name]) {
                    throw new Error('cannot register existing reader', name);
                }
                READERS[name] = reader;
            },
            setReaders: function(readers) {
                config.readers = readers;
                _barcodeReaders.length = 0;
                initReaders();
            },
        };
    },
};
<|endoftext|>


<commit_before>// Load the book metadata into MongoDB from book_metadata.json

var databaseURI = "localhost:27017/bldata";
var collections = ["bookmeta"];
var db = require("mongojs").connect(databaseURI, collections);

var fs = require('fs');
var file = '../../../data/bldata/imagedirectory/book_metadata.json';

var bookdata;
var waitingCount = 0;
fs.readFile(file, 'utf8', function (err, data) {
	if (err) {
		console.log('Error: ' + err);
		return;
	}

	bookdata = JSON.parse(data);
	for (var i = 0; i < bookdata.length; i++) {
		var meta = bookdata[i];
		meta._id = meta.identifier;
		// add to Mongo:
		waitingCount++;
		db.bookmeta.update({"_id" : meta._id}, meta, {"upsert" : true}, function() { waitingCount--;});
	}

	// give save thread a chance to finish by waiting a second
	console.log("Waiting to finish..");
	waitForFinish();
});

function waitForFinish() {
	setTimeout((function() {
		console.log(waitingCount);
		if (waitingCount <= 0) {
			process.exit();
		} else {
			waitForFinish();
		}
	}), 1000);
}
<commit_msg>Better comment<commit_after>// Load the book metadata into MongoDB from book_metadata.json

var databaseURI = "localhost:27017/bldata";
var collections = ["bookmeta"];
var db = require("mongojs").connect(databaseURI, collections);

var fs = require('fs');
var file = '../../../data/bldata/imagedirectory/book_metadata.json';

var bookdata;
var waitingCount = 0;
fs.readFile(file, 'utf8', function (err, data) {
	if (err) {
		console.log('Error: ' + err);
		return;
	}

	bookdata = JSON.parse(data);
	for (var i = 0; i < bookdata.length; i++) {
		var meta = bookdata[i];
		meta._id = meta.identifier;
		// add to Mongo:
		waitingCount++;
		db.bookmeta.update({"_id" : meta._id}, meta, {"upsert" : true}, function() { waitingCount--;});
	}

	// wait for all the updates to finish (they'll be happening asynchronously!)
	console.log("Waiting to finish..");
	waitForFinish();
});

function waitForFinish() {
	setTimeout((function() {
		console.log(waitingCount);
		if (waitingCount <= 0) {
			process.exit();
		} else {
			waitForFinish();
		}
	}), 1000);
}
<|endoftext|>