<commit_before>/**
 *
 * Requires the following icnlude in the django template:
 *
 *     {% include "extjshelpers/AssignmentGroupOverviewExtjsClasses.django.html" %}
 */
Ext.define('devilry.extjshelpers.assignmentgroup.AssignmentGroupOverview', {
    extend: 'Ext.container.Container',
    alias: 'widget.assignmentgroupoverview',
    cls: 'widget-assignmentgroupoverview',
    requires: [
        'devilry.extjshelpers.assignmentgroup.DeliveryInfo',
        'devilry.extjshelpers.assignmentgroup.AssignmentGroupInfo',
        'devilry.extjshelpers.assignmentgroup.StaticFeedbackInfo',
        'devilry.extjshelpers.assignmentgroup.StaticFeedbackEditor',
        'devilry.extjshelpers.assignmentgroup.AssignmentGroupTitle',
        'devilry.extjshelpers.assignmentgroup.AssignmentGroupTodoListWindow',
        'devilry.extjshelpers.assignmentgroup.DeliveriesGroupedByDeadline',
        'devilry.extjshelpers.assignmentgroup.IsOpen',
        'devilry.extjshelpers.SingleRecordContainer'
    ],

    //title: 'Assignment group',

    config: {
        /**
         * @cfg
         * Enable creation of new feedbacks? Defaults to ``false``.
         * See: {@link devilry.extjshelpers.assignmentgroup.DeliveryInfo#canExamine}.
         *
         * When this is ``true``, the authenticated user still needs to have
         * permission to POST new feedbacks for the view to work.
         */
        canExamine: false,

        /**
         * @cfg
         * AssignmentGroup ID.
         */
        assignmentgroupid: undefined,

        /**
         * @cfg
         * Use the administrator RESTful interface to store drafts? If this is
         * ``false``, we use the examiner RESTful interface.
         */
        isAdministrator: false
    },

    constructor: function(config) {
        this.initConfig(config);
        this.callParent([config]);
    },

    initComponent: function() {
        this.createAttributes();
        this.createLayout();
        this.callParent(arguments);
        this.loadAssignmentgroupRecord(); // NOTE: Must come after createLayout() because components listen for the setRecord event
        this.selectDeliveryIfInQueryString();
    },

    /**
     * @private
     */
    createAttributes: function() {
        this.assignmentgroup_recordcontainer = Ext.create('devilry.extjshelpers.SingleRecordContainer');
        this.delivery_recordcontainer = Ext.create('devilry.extjshelpers.SingleRecordContainer');
        this.gradeeditor_config_recordcontainer = Ext.create('devilry.extjshelpers.SingleRecordContainer');

        this.role = !this.canExamine? 'student': this.isAdministrator? 'administrator': 'examiner';
        this.assignmentgroupmodel = Ext.ModelManager.getModel(this.getSimplifiedClassName('SimplifiedAssignmentGroup'));
        this.deliverymodel = Ext.ModelManager.getModel(this.getSimplifiedClassName('SimplifiedDelivery'));
        this.filemetastore = Ext.data.StoreManager.lookup(this.getSimplifiedClassName('SimplifiedFileMetaStore'));
        this.staticfeedbackstore = Ext.data.StoreManager.lookup(this.getSimplifiedClassName('SimplifiedStaticFeedbackStore'));
        this.deadlinemodel = Ext.ModelManager.getModel(this.getSimplifiedClassName('SimplifiedDeadline'));

        if(this.canExamine) {
            this.gradeeditor_config_model = Ext.ModelManager.getModel(Ext.String.format(
                'devilry.apps.gradeeditors.simplified.{0}.SimplifiedConfig',
                this.role
            ));

            this.assignmentgroupstore = Ext.data.StoreManager.lookup(this.getSimplifiedClassName('SimplifiedAssignmentGroupStore'));
        }
    },

    /**
     * @private
     */
    loadAssignmentgroupRecord: function() {
        this.assignmentgroupmodel.load(this.assignmentgroupid, {
            scope: this,
            success: function(record) {
                this.assignmentgroup_recordcontainer.setRecord(record);
                this.loadGradeEditorConfigModel();

            },
            failure: function() {
                // TODO: Handle errors
            }
        });
    },

    /**
     * @private
     */
    loadGradeEditorConfigModel: function() {
        if(this.canExamine) {
            this.gradeeditor_config_model.load(this.assignmentgroup_recordcontainer.record.data.parentnode, {
                scope: this,
                success: function(record) {
                    this.gradeeditor_config_recordcontainer.setRecord(record);
                },
                failure: function() {
                    // TODO: Handle errors
                }
            });
        }
    },

    /**
     * @private
     */
    getSimplifiedClassName: function(name) {
        var classname = Ext.String.format(
            'devilry.apps.{0}.simplified.{1}',
            this.role, name
        );
        return classname;

    },

    /**
     * @private
     */
    showFeedbackPanel: function() {
        this.feedbackPanel.show();
    },

    /**
     * @private
     */
    createLayout: function() {
        this.feedbackPanel = Ext.widget(this.canExamine? 'staticfeedbackeditor': 'staticfeedbackinfo', {
            title: 'Feedback',
            staticfeedbackstore: this.staticfeedbackstore,
            hidden: true,
            region: 'center',
            delivery_recordcontainer: this.delivery_recordcontainer,
            isAdministrator: this.isAdministrator, // Only required by staticfeedbackeditor
            assignmentgroup_recordcontainer: this.assignmentgroup_recordcontainer, // Only required by staticfeedbackeditor
            deadlinemodel: this.deadlinemodel, // Only required by staticfeedbackeditor
            assignmentgroupmodel: this.assignmentgroupmodel, // Only required by staticfeedbackeditor
            gradeeditor_config_recordcontainer: this.gradeeditor_config_recordcontainer // Only required by staticfeedbackeditor
        });
        if(this.delivery_recordcontainer.record) {
            this.showFeedbackPanel();
        } else {
            this.delivery_recordcontainer.addListener('setRecord', this.showFeedbackPanel, this);
        }

        Ext.apply(this, {
            layout: {
                type: 'vbox',
                align: 'stretch'
            },
            items: [{
                xtype: 'assignmentgrouptitle',
                singlerecordontainer: this.assignmentgroup_recordcontainer
            }, {
                xtype: 'container',
                layout: 'border',
                flex: 1,
                border: false,
                items: [{
                    xtype: 'container',
                    region: 'west',
                    width: 250,
                    layout: {
                        type: 'vbox',
                        align: 'stretch'
                    },
                    items: [{
                        xtype: 'container',
                        layout: {
                            type: 'hbox'
                        },
                        items: [{
                            xtype: 'assignmentgroup_isopen',
                            assignmentgroup_recordcontainer: this.assignmentgroup_recordcontainer,
                            canExamine: this.canExamine
                        }, {
                            xtype: 'button',
                            hidden: !this.canExamine,
                            text: 'To-do',
                            scale: 'large',
                            listeners: {
                                scope: this,
                                click: function() {
                                    Ext.create('devilry.extjshelpers.assignmentgroup.AssignmentGroupTodoListWindow', {
                                        assignmentgroupstore: this.assignmentgroupstore,
                                        assignmentgroup_recordcontainer: this.assignmentgroup_recordcontainer
                                    }).show();
                                }
                            }
                        }]
                    }, {
                        xtype: 'deliveriesgroupedbydeadline',
                        assignmentgroup_recordcontainer: this.assignmentgroup_recordcontainer,
                        delivery_recordcontainer: this.delivery_recordcontainer,
                        flex: 1
                    //}, {
                        //xtype: 'assignmentgroupinfo',
                        //assignmentgroup_recordcontainer: this.assignmentgroup_recordcontainer,
                        //delivery_recordcontainer: this.delivery_recordcontainer,
                        //assignmentgroupstore: this.assignmentgroupstore,
                        //deliverymodel: this.deliverymodel,
                        //deadlinemodel: this.deadlinemodel,
                        //canExamine: this.canExamine
                    //}, {
                        //xtype: 'deliveryinfo',
                        //title: 'Delivery',
                        //filemetastore: this.filemetastore,
                        //delivery_recordcontainer: this.delivery_recordcontainer,
                        //deliverymodel: this.deliverymodel,
                        //assignmentgroup_recordcontainer: this.assignmentgroup_recordcontainer,
                        //listeners: {
                            //scope: this,
                            //deliveriesLoaded: this.onDeliveriesLoaded
                        //}
                    }]
                }, this.feedbackPanel]
            }]
        });
    },

    /**
     * @private
     */
    onDeliveriesLoaded: function(deliverystore) {
        //var assignmentgroupdetails = this.down('assignmentgroupdetails');
        //assignmentgroupdetails.extradata.numDeliveries = deliverystore.totalCount;
        //assignmentgroupdetails.updateBody();
    },

    /**
     * @private
     */
    selectDeliveryIfInQueryString: function() {
        var query = Ext.Object.fromQueryString(window.location.search);
        if(query.deliveryid) {
            var deliveryid = parseInt(query.deliveryid);
            this.deliverymodel.load(deliveryid, {
                scope: this,
                success: function(record) {
                    if(this.assignmentgroupid == record.data.deadline__assignment_group) {
                        this.delivery_recordcontainer.setRecord(record);
                    } else {
                        throw Ext.String.format(
                            'Delivery {0} is not in AssignmentGroup {1}',
                            deliveryid,
                            this.assignmentgroupid
                        );
                    }
                },
                failure: function() {
                    // TODO: Handle errors
                }
            });
        } else {
            this.down('deliveryinfo').onOtherDeliveries();
        }
    }
});
<commit_msg>apps.extjshelpers...AssignmentGroupOverview: Layout.<commit_after>/**
 *
 * Requires the following icnlude in the django template:
 *
 *     {% include "extjshelpers/AssignmentGroupOverviewExtjsClasses.django.html" %}
 */
Ext.define('devilry.extjshelpers.assignmentgroup.AssignmentGroupOverview', {
    extend: 'Ext.container.Container',
    alias: 'widget.assignmentgroupoverview',
    cls: 'widget-assignmentgroupoverview',
    requires: [
        'devilry.extjshelpers.assignmentgroup.DeliveryInfo',
        'devilry.extjshelpers.assignmentgroup.AssignmentGroupInfo',
        'devilry.extjshelpers.assignmentgroup.StaticFeedbackInfo',
        'devilry.extjshelpers.assignmentgroup.StaticFeedbackEditor',
        'devilry.extjshelpers.assignmentgroup.AssignmentGroupTitle',
        'devilry.extjshelpers.assignmentgroup.AssignmentGroupTodoListWindow',
        'devilry.extjshelpers.assignmentgroup.DeliveriesGroupedByDeadline',
        'devilry.extjshelpers.assignmentgroup.IsOpen',
        'devilry.extjshelpers.SingleRecordContainer'
    ],

    //title: 'Assignment group',

    config: {
        /**
         * @cfg
         * Enable creation of new feedbacks? Defaults to ``false``.
         * See: {@link devilry.extjshelpers.assignmentgroup.DeliveryInfo#canExamine}.
         *
         * When this is ``true``, the authenticated user still needs to have
         * permission to POST new feedbacks for the view to work.
         */
        canExamine: false,

        /**
         * @cfg
         * AssignmentGroup ID.
         */
        assignmentgroupid: undefined,

        /**
         * @cfg
         * Use the administrator RESTful interface to store drafts? If this is
         * ``false``, we use the examiner RESTful interface.
         */
        isAdministrator: false
    },

    constructor: function(config) {
        this.initConfig(config);
        this.callParent([config]);
    },

    initComponent: function() {
        this.createAttributes();
        this.createLayout();
        this.callParent(arguments);
        this.loadAssignmentgroupRecord(); // NOTE: Must come after createLayout() because components listen for the setRecord event
        this.selectDeliveryIfInQueryString();
    },

    /**
     * @private
     */
    createAttributes: function() {
        this.assignmentgroup_recordcontainer = Ext.create('devilry.extjshelpers.SingleRecordContainer');
        this.delivery_recordcontainer = Ext.create('devilry.extjshelpers.SingleRecordContainer');
        this.gradeeditor_config_recordcontainer = Ext.create('devilry.extjshelpers.SingleRecordContainer');

        this.role = !this.canExamine? 'student': this.isAdministrator? 'administrator': 'examiner';
        this.assignmentgroupmodel = Ext.ModelManager.getModel(this.getSimplifiedClassName('SimplifiedAssignmentGroup'));
        this.deliverymodel = Ext.ModelManager.getModel(this.getSimplifiedClassName('SimplifiedDelivery'));
        this.filemetastore = Ext.data.StoreManager.lookup(this.getSimplifiedClassName('SimplifiedFileMetaStore'));
        this.staticfeedbackstore = Ext.data.StoreManager.lookup(this.getSimplifiedClassName('SimplifiedStaticFeedbackStore'));
        this.deadlinemodel = Ext.ModelManager.getModel(this.getSimplifiedClassName('SimplifiedDeadline'));

        if(this.canExamine) {
            this.gradeeditor_config_model = Ext.ModelManager.getModel(Ext.String.format(
                'devilry.apps.gradeeditors.simplified.{0}.SimplifiedConfig',
                this.role
            ));

            this.assignmentgroupstore = Ext.data.StoreManager.lookup(this.getSimplifiedClassName('SimplifiedAssignmentGroupStore'));
        }
    },

    /**
     * @private
     */
    loadAssignmentgroupRecord: function() {
        this.assignmentgroupmodel.load(this.assignmentgroupid, {
            scope: this,
            success: function(record) {
                this.assignmentgroup_recordcontainer.setRecord(record);
                this.loadGradeEditorConfigModel();

            },
            failure: function() {
                // TODO: Handle errors
            }
        });
    },

    /**
     * @private
     */
    loadGradeEditorConfigModel: function() {
        if(this.canExamine) {
            this.gradeeditor_config_model.load(this.assignmentgroup_recordcontainer.record.data.parentnode, {
                scope: this,
                success: function(record) {
                    this.gradeeditor_config_recordcontainer.setRecord(record);
                },
                failure: function() {
                    // TODO: Handle errors
                }
            });
        }
    },

    /**
     * @private
     */
    getSimplifiedClassName: function(name) {
        var classname = Ext.String.format(
            'devilry.apps.{0}.simplified.{1}',
            this.role, name
        );
        return classname;

    },

    /**
     * @private
     */
    showFeedbackPanel: function() {
        this.feedbackPanel.show();
    },

    /**
     * @private
     */
    createLayout: function() {
        this.feedbackPanel = Ext.widget(this.canExamine? 'staticfeedbackeditor': 'staticfeedbackinfo', {
            title: 'Feedback',
            staticfeedbackstore: this.staticfeedbackstore,
            hidden: true,
            region: 'center',
            delivery_recordcontainer: this.delivery_recordcontainer,
            isAdministrator: this.isAdministrator, // Only required by staticfeedbackeditor
            assignmentgroup_recordcontainer: this.assignmentgroup_recordcontainer, // Only required by staticfeedbackeditor
            deadlinemodel: this.deadlinemodel, // Only required by staticfeedbackeditor
            assignmentgroupmodel: this.assignmentgroupmodel, // Only required by staticfeedbackeditor
            gradeeditor_config_recordcontainer: this.gradeeditor_config_recordcontainer // Only required by staticfeedbackeditor
        });
        if(this.delivery_recordcontainer.record) {
            this.showFeedbackPanel();
        } else {
            this.delivery_recordcontainer.addListener('setRecord', this.showFeedbackPanel, this);
        }

        Ext.apply(this, {
            layout: {
                type: 'vbox',
                align: 'stretch'
            },
            items: [{
                xtype: 'assignmentgrouptitle',
                singlerecordontainer: this.assignmentgroup_recordcontainer
            }, {
                xtype: 'container',
                layout: 'border',
                style: 'background-color: transparent',
                flex: 1,
                border: false,
                items: [{
                    xtype: 'container',
                    region: 'west',
                    margin: {right: 10},
                    width: 250,
                    layout: {
                        type: 'vbox',
                        align: 'stretch'
                    },
                    items: [{
                        xtype: 'container',
                        layout: {
                            type: 'hbox'
                        },
                        items: [{
                            xtype: 'assignmentgroup_isopen',
                            assignmentgroup_recordcontainer: this.assignmentgroup_recordcontainer,
                            canExamine: this.canExamine
                        }, {xtype: 'box', width: 10}, {
                            xtype: 'button',
                            hidden: !this.canExamine,
                            text: 'To-do',
                            scale: 'large',
                            listeners: {
                                scope: this,
                                click: function() {
                                    Ext.create('devilry.extjshelpers.assignmentgroup.AssignmentGroupTodoListWindow', {
                                        assignmentgroupstore: this.assignmentgroupstore,
                                        assignmentgroup_recordcontainer: this.assignmentgroup_recordcontainer
                                    }).show();
                                }
                            }
                        }]
                    }, {
                        xtype: 'deliveriesgroupedbydeadline',
                        margin: {top: 10},
                        assignmentgroup_recordcontainer: this.assignmentgroup_recordcontainer,
                        delivery_recordcontainer: this.delivery_recordcontainer,
                        flex: 1
                    //}, {
                        //xtype: 'assignmentgroupinfo',
                        //assignmentgroup_recordcontainer: this.assignmentgroup_recordcontainer,
                        //delivery_recordcontainer: this.delivery_recordcontainer,
                        //assignmentgroupstore: this.assignmentgroupstore,
                        //deliverymodel: this.deliverymodel,
                        //deadlinemodel: this.deadlinemodel,
                        //canExamine: this.canExamine
                    //}, {
                        //xtype: 'deliveryinfo',
                        //title: 'Delivery',
                        //filemetastore: this.filemetastore,
                        //delivery_recordcontainer: this.delivery_recordcontainer,
                        //deliverymodel: this.deliverymodel,
                        //assignmentgroup_recordcontainer: this.assignmentgroup_recordcontainer,
                        //listeners: {
                            //scope: this,
                            //deliveriesLoaded: this.onDeliveriesLoaded
                        //}
                    }]
                }, this.feedbackPanel]
            }]
        });
    },

    /**
     * @private
     */
    onDeliveriesLoaded: function(deliverystore) {
        //var assignmentgroupdetails = this.down('assignmentgroupdetails');
        //assignmentgroupdetails.extradata.numDeliveries = deliverystore.totalCount;
        //assignmentgroupdetails.updateBody();
    },

    /**
     * @private
     */
    selectDeliveryIfInQueryString: function() {
        var query = Ext.Object.fromQueryString(window.location.search);
        if(query.deliveryid) {
            var deliveryid = parseInt(query.deliveryid);
            this.deliverymodel.load(deliveryid, {
                scope: this,
                success: function(record) {
                    if(this.assignmentgroupid == record.data.deadline__assignment_group) {
                        this.delivery_recordcontainer.setRecord(record);
                    } else {
                        throw Ext.String.format(
                            'Delivery {0} is not in AssignmentGroup {1}',
                            deliveryid,
                            this.assignmentgroupid
                        );
                    }
                },
                failure: function() {
                    // TODO: Handle errors
                }
            });
        } else {
            this.down('deliveryinfo').onOtherDeliveries();
        }
    }
});
<|endoftext|>


<commit_before>app.controller(
    'UploadController',
    [
        '$scope',
        '$controller',
        '$modal',
        'ModelService',
        function ($scope, ModelService) {
            // file reader stuff
            $scope.fileReaderSupported = window.FileReader != null;
            $scope.hasUploader = function (index) {
                return $scope.upload[index] != null;
            };
            $scope.abort = function (index) {
                $scope.upload[index].abort();
                $scope.upload[index] = null;
            };

            $scope.onFileSelect = function ($files) {
                $scope.file_name = null;
                $scope.csv_data = null;
                $scope.csv_errors = [];
                if ($files.length != 1) {
                    $scope.csv_errors.push('Please drag only one file at a time.');
                } else {
                    parseCSV($files[0])
                }
            };

            function parseCSV(file) {
                    $scope.file_name = file.name;

                    // parse CSV file
                    Papa.parse(file, {
                        header: true,
                        complete: function (results) {
                            validateData(results.data);
                            $scope.csv_data = results.data;
                            $scope.$apply();
                        }
                    });
            }

            function validateData(data) {
                var distinct_cohorts = [];
                var distinct_notebooks_tmp = [];  // array of strings (name)
                $scope.distinct_notebooks = [];  // array of objects
                var distinct_networks = [];  // array of strings (name)
                var distinct_participants_tmp = [];  // array of strings (name)
                $scope.distinct_participants = [];  // array of objects

                var distinct_analytes_tmp = [];  // array of strings (name)
                $scope.distinct_analytes = [];  // array of objects

                // analyte regex pattern to strip optional bead number
                var analyte_pattern = /^.*(?=\s\(\d+\)$)/;
                var analyte_result;

                var distinct_isotypes_tmp = [];  // array of strings (name)
                $scope.distinct_isotypes = [];  // array of objects

                var distinct_conjugates_tmp = [];  // array of strings (name)
                $scope.distinct_conjugates = [];  // array of objects

                // gather validation data for every data point
                data.forEach(function (d) {
                    // get distinct cohorts, must be only one and must match
                    // the current cohort
                    if (typeof(d.Cohort) == "undefined") {
                        $scope.csv_errors.push("Cohort field is required");
                    } else {
                        if (distinct_cohorts.indexOf(d.Cohort) == -1) {
                            distinct_cohorts.push(d.Cohort);
                        }
                    }

                    // get distinct notebooks. this field is required but there
                    // are no additional rules for this one
                    // but we will show the new ones to the user
                    if (typeof(d['Notebook Number']) == "undefined") {
                        $scope.csv_errors.push("Notebook field is required");
                    } else {
                        if (distinct_notebooks_tmp.indexOf(d['Notebook Number']) == -1) {
                            distinct_notebooks_tmp.push(d['Notebook Number']);
                        }
                    }

                    // get distinct networks (required)
                    if (typeof(d['Network']) == "undefined") {
                        $scope.csv_errors.push("Network field is required");
                    } else {
                        if (distinct_networks.indexOf(d['Network']) == -1) {
                            distinct_networks.push(d['Network']);
                        }
                    }

                    // get distinct participants (required)
                    if (typeof(d['Participant ID']) == "undefined") {
                        $scope.csv_errors.push("Participant ID field is required");
                    } else {
                        if (distinct_participants_tmp.indexOf(d['Participant ID']) == -1) {
                            distinct_participants_tmp.push(d['Participant ID']);

                            // determine if any new participants are present
                            var existing_participant_idx = null;

                            for (var i= 0, len = $scope.participants.length; i < len; i++) {
                                if ($scope.participants[i].code == d['Participant ID']) {
                                    existing_participant_idx = i;
                                    break;
                                }
                            }

                            if (existing_participant_idx != null) {
                                // existing participant:
                                // verify species matches this record.
                                // this is done only for this first encountered
                                // record, all others will be assumed to be the
                                // same, checking this would potentially be
                                // quite expensive
                                if (d['Species'] != $scope.participants[existing_participant_idx].species_name) {
                                    $scope.csv_errors.push("Species for participant " + d['Participant ID'] + " does not match the server");
                                }
                            }

                            $scope.distinct_participants.push(
                                {
                                    code: d['Participant ID'],
                                    new: existing_participant_idx == null
                                }
                            );
                        }
                    }

                    // get distinct analytes (required)
                    if (typeof(d['Analyte']) == "undefined") {
                        $scope.csv_errors.push("Analyte field is required");
                    } else {
                        // need to strip the bead number off analyte string
                        // if present
                        analyte_result = analyte_pattern.exec(d['Analyte']);
                        if (analyte_result == null) {
                            // doesn't contain a trailing bead number
                            analyte_result = d['Analyte'];
                        } else {
                            // contains a bead number, get everything but bead
                            analyte_result = analyte_result[0];
                        }

                        if (distinct_analytes_tmp.indexOf(analyte_result) == -1) {
                            distinct_analytes_tmp.push(analyte_result);

                            // determine if any new analytes are present
                            var existing_analyte_idx = null;

                            for (var i= 0, len = $scope.analytes.length; i < len; i++) {
                                if ($scope.analytes[i].name == analyte_result) {
                                    existing_analyte_idx = i;
                                    break;
                                }
                            }

                            if (existing_analyte_idx == null) {
                                // analyte doesn't exist, uh, that's a problem
                                $scope.csv_errors.push("Analyte \"" + analyte_result + "\" does not exist on the server");
                            }

                            $scope.distinct_analytes.push(
                                {
                                    name: analyte_result,
                                    new: existing_analyte_idx == null
                                }
                            );
                        }
                    }

                    // get distinct isotypes (required)
                    if (typeof(d['Isotype']) == "undefined") {
                        $scope.csv_errors.push("Isotype field is required");
                    } else {
                        if (distinct_isotypes_tmp.indexOf(d['Isotype']) == -1) {
                            distinct_isotypes_tmp.push(d['Isotype']);

                            // determine if any new isotypes are present
                            var existing_isotype_idx = null;

                            for (var i= 0, len = $scope.isotypes.length; i < len; i++) {
                                if ($scope.isotypes[i].name == d['Isotype']) {
                                    existing_isotype_idx = i;
                                    break;
                                }
                            }

                            if (existing_isotype_idx == null) {
                                // isotype doesn't exist, uh, that's a problem
                                $scope.csv_errors.push("Isotype \"" + d['Isotype'] + "\" does not exist on the server");
                            }

                            $scope.distinct_isotypes.push(
                                {
                                    name: d['Isotype'],
                                    new: existing_isotype_idx == null
                                }
                            );
                        }
                    }

                    // get distinct conjugates (required)
                    if (typeof(d['Conjugate']) == "undefined") {
                        $scope.csv_errors.push("Conjugate field is required");
                    } else {
                        if (distinct_conjugates_tmp.indexOf(d['Conjugate']) == -1) {
                            distinct_conjugates_tmp.push(d['Conjugate']);

                            // determine if any new conjugates are present
                            var existing_conjugate_idx = null;

                            for (var i= 0, len = $scope.conjugates.length; i < len; i++) {
                                if ($scope.conjugates[i].name == d['Conjugate']) {
                                    existing_conjugate_idx = i;
                                    break;
                                }
                            }

                            if (existing_conjugate_idx == null) {
                                // conjugate doesn't exist, uh, that's a problem
                                $scope.csv_errors.push("Conjugate \"" + d['Conjugate'] + "\" does not exist on the server");
                            }

                            $scope.distinct_conjugates.push(
                                {
                                    name: d['Conjugate'],
                                    new: existing_conjugate_idx == null
                                }
                            );
                        }
                    }

                    // validate dilution is present and a positive number
                    if (typeof(d['Dilution']) == "undefined") {
                        $scope.csv_errors.push("Dilution field is required");
                    } else if (isNaN(d['Dilution'])) {
                        $scope.csv_errors.push("Dilution value must be a positive number. Found: " + d['Dilution']);
                    } else if (parseFloat(d['Dilution']) <= 0) {
                        $scope.csv_errors.push("Dilution value must be a positive number. Found: " + d['Dilution']);
                    }

                    // validate FI-Bkgd is present and a number
                    if (typeof(d['FI-Bkgd']) == "undefined") {
                        $scope.csv_errors.push("FI-Bkgd field is required");
                    } else if (isNaN(d['FI-Bkgd'])) {
                        $scope.csv_errors.push("FI-Bkgd value must be a number. Found: " + d['FI-Bkgd']);
                    }
                });

                // Now check all our validation data

                // only one cohort should be present
                if (distinct_cohorts.length > 1) {
                    $scope.csv_errors.push("Multiple cohorts found in CSV file. Data can only be uploaded for one cohort at a time");
                }

                // cohort must match current cohort
                if (distinct_cohorts[0] != $scope.current_cohort.name) {
                    $scope.csv_errors.push("Cohort in CSV file doesn't match this cohort");
                }

                // only one network should be present and should match the
                // cohort's network
                if (distinct_networks.length > 1) {
                    $scope.csv_errors.push("Multiple networks found in CSV file. Data can only be uploaded for one network at a time");
                }

                // cohort must match current cohort
                if (distinct_networks[0] != $scope.current_cohort.network_name) {
                    $scope.csv_errors.push("Network in CSV file doesn't match this cohort's network");
                }

                // determine if any new notebooks are present
                distinct_notebooks_tmp.forEach(function (n) {
                    var new_nb = false;
                    if ($scope.notebooks.indexOf(n) == -1) {
                        new_nb = true;
                    }
                    $scope.distinct_notebooks.push(
                        {
                            name: n,
                            new: new_nb
                        }
                    );
                });
            }
        }
    ]
);<commit_msg>validate CV is a percentage<commit_after>app.controller(
    'UploadController',
    [
        '$scope',
        '$controller',
        '$modal',
        'ModelService',
        function ($scope, ModelService) {
            // file reader stuff
            $scope.fileReaderSupported = window.FileReader != null;
            $scope.hasUploader = function (index) {
                return $scope.upload[index] != null;
            };
            $scope.abort = function (index) {
                $scope.upload[index].abort();
                $scope.upload[index] = null;
            };

            $scope.onFileSelect = function ($files) {
                $scope.file_name = null;
                $scope.csv_data = null;
                $scope.csv_errors = [];
                if ($files.length != 1) {
                    $scope.csv_errors.push('Please drag only one file at a time.');
                } else {
                    parseCSV($files[0])
                }
            };

            function parseCSV(file) {
                    $scope.file_name = file.name;

                    // parse CSV file
                    Papa.parse(file, {
                        header: true,
                        complete: function (results) {
                            validateData(results.data);
                            $scope.csv_data = results.data;
                            $scope.$apply();
                        }
                    });
            }

            function validateData(data) {
                var distinct_cohorts = [];
                var distinct_notebooks_tmp = [];  // array of strings (name)
                $scope.distinct_notebooks = [];  // array of objects
                var distinct_networks = [];  // array of strings (name)
                var distinct_participants_tmp = [];  // array of strings (name)
                $scope.distinct_participants = [];  // array of objects

                var distinct_analytes_tmp = [];  // array of strings (name)
                $scope.distinct_analytes = [];  // array of objects

                // analyte regex pattern to strip optional bead number
                var analyte_pattern = /^.*(?=\s\(\d+\)$)/;
                var analyte_result;

                var distinct_isotypes_tmp = [];  // array of strings (name)
                $scope.distinct_isotypes = [];  // array of objects

                var distinct_conjugates_tmp = [];  // array of strings (name)
                $scope.distinct_conjugates = [];  // array of objects

                // CV regex pattern to find number with optional '%'
                var cv_pattern = /^\d+\.?\d*(?=\%?$)/;
                var cv_result;

                // gather validation data for every data point
                data.forEach(function (d) {
                    // get distinct cohorts, must be only one and must match
                    // the current cohort
                    if (typeof(d.Cohort) == "undefined") {
                        $scope.csv_errors.push("Cohort field is required");
                    } else {
                        if (distinct_cohorts.indexOf(d.Cohort) == -1) {
                            distinct_cohorts.push(d.Cohort);
                        }
                    }

                    // get distinct notebooks. this field is required but there
                    // are no additional rules for this one
                    // but we will show the new ones to the user
                    if (typeof(d['Notebook Number']) == "undefined") {
                        $scope.csv_errors.push("Notebook field is required");
                    } else {
                        if (distinct_notebooks_tmp.indexOf(d['Notebook Number']) == -1) {
                            distinct_notebooks_tmp.push(d['Notebook Number']);
                        }
                    }

                    // get distinct networks (required)
                    if (typeof(d['Network']) == "undefined") {
                        $scope.csv_errors.push("Network field is required");
                    } else {
                        if (distinct_networks.indexOf(d['Network']) == -1) {
                            distinct_networks.push(d['Network']);
                        }
                    }

                    // get distinct participants (required)
                    if (typeof(d['Participant ID']) == "undefined") {
                        $scope.csv_errors.push("Participant ID field is required");
                    } else {
                        if (distinct_participants_tmp.indexOf(d['Participant ID']) == -1) {
                            distinct_participants_tmp.push(d['Participant ID']);

                            // determine if any new participants are present
                            var existing_participant_idx = null;

                            for (var i= 0, len = $scope.participants.length; i < len; i++) {
                                if ($scope.participants[i].code == d['Participant ID']) {
                                    existing_participant_idx = i;
                                    break;
                                }
                            }

                            if (existing_participant_idx != null) {
                                // existing participant:
                                // verify species matches this record.
                                // this is done only for this first encountered
                                // record, all others will be assumed to be the
                                // same, checking this would potentially be
                                // quite expensive
                                if (d['Species'] != $scope.participants[existing_participant_idx].species_name) {
                                    $scope.csv_errors.push("Species for participant " + d['Participant ID'] + " does not match the server");
                                }
                            }

                            $scope.distinct_participants.push(
                                {
                                    code: d['Participant ID'],
                                    new: existing_participant_idx == null
                                }
                            );
                        }
                    }

                    // get distinct analytes (required)
                    if (typeof(d['Analyte']) == "undefined") {
                        $scope.csv_errors.push("Analyte field is required");
                    } else {
                        // need to strip the bead number off analyte string
                        // if present
                        analyte_result = analyte_pattern.exec(d['Analyte']);
                        if (analyte_result == null) {
                            // doesn't contain a trailing bead number
                            analyte_result = d['Analyte'];
                        } else {
                            // contains a bead number, get everything but bead
                            analyte_result = analyte_result[0];
                        }

                        if (distinct_analytes_tmp.indexOf(analyte_result) == -1) {
                            distinct_analytes_tmp.push(analyte_result);

                            // determine if any new analytes are present
                            var existing_analyte_idx = null;

                            for (var i= 0, len = $scope.analytes.length; i < len; i++) {
                                if ($scope.analytes[i].name == analyte_result) {
                                    existing_analyte_idx = i;
                                    break;
                                }
                            }

                            if (existing_analyte_idx == null) {
                                // analyte doesn't exist, uh, that's a problem
                                $scope.csv_errors.push("Analyte \"" + analyte_result + "\" does not exist on the server");
                            }

                            $scope.distinct_analytes.push(
                                {
                                    name: analyte_result,
                                    new: existing_analyte_idx == null
                                }
                            );
                        }
                    }

                    // get distinct isotypes (required)
                    if (typeof(d['Isotype']) == "undefined") {
                        $scope.csv_errors.push("Isotype field is required");
                    } else {
                        if (distinct_isotypes_tmp.indexOf(d['Isotype']) == -1) {
                            distinct_isotypes_tmp.push(d['Isotype']);

                            // determine if any new isotypes are present
                            var existing_isotype_idx = null;

                            for (var i= 0, len = $scope.isotypes.length; i < len; i++) {
                                if ($scope.isotypes[i].name == d['Isotype']) {
                                    existing_isotype_idx = i;
                                    break;
                                }
                            }

                            if (existing_isotype_idx == null) {
                                // isotype doesn't exist, uh, that's a problem
                                $scope.csv_errors.push("Isotype \"" + d['Isotype'] + "\" does not exist on the server");
                            }

                            $scope.distinct_isotypes.push(
                                {
                                    name: d['Isotype'],
                                    new: existing_isotype_idx == null
                                }
                            );
                        }
                    }

                    // get distinct conjugates (required)
                    if (typeof(d['Conjugate']) == "undefined") {
                        $scope.csv_errors.push("Conjugate field is required");
                    } else {
                        if (distinct_conjugates_tmp.indexOf(d['Conjugate']) == -1) {
                            distinct_conjugates_tmp.push(d['Conjugate']);

                            // determine if any new conjugates are present
                            var existing_conjugate_idx = null;

                            for (var i= 0, len = $scope.conjugates.length; i < len; i++) {
                                if ($scope.conjugates[i].name == d['Conjugate']) {
                                    existing_conjugate_idx = i;
                                    break;
                                }
                            }

                            if (existing_conjugate_idx == null) {
                                // conjugate doesn't exist, uh, that's a problem
                                $scope.csv_errors.push("Conjugate \"" + d['Conjugate'] + "\" does not exist on the server");
                            }

                            $scope.distinct_conjugates.push(
                                {
                                    name: d['Conjugate'],
                                    new: existing_conjugate_idx == null
                                }
                            );
                        }
                    }

                    // validate dilution is present and a positive number
                    if (typeof(d['Dilution']) == "undefined") {
                        $scope.csv_errors.push("Dilution field is required");
                    } else if (isNaN(d['Dilution'])) {
                        $scope.csv_errors.push("Dilution value must be a positive number. Found: " + d['Dilution']);
                    } else if (parseFloat(d['Dilution']) <= 0) {
                        $scope.csv_errors.push("Dilution value must be a positive number. Found: " + d['Dilution']);
                    }

                    // validate FI-Bkgd is present and a number
                    if (typeof(d['FI-Bkgd']) == "undefined") {
                        $scope.csv_errors.push("FI-Bkgd field is required");
                    } else if (isNaN(d['FI-Bkgd'])) {
                        $scope.csv_errors.push("FI-Bkgd value must be a number. Found: " + d['FI-Bkgd']);
                    }

                    // validate FI-Bkgd is present and a number
                    if (typeof(d['FI-Bkgd-Blank']) == "undefined") {
                        $scope.csv_errors.push("FI-Bkgd-Blank field is required");
                    } else if (isNaN(d['FI-Bkgd-Blank'])) {
                        $scope.csv_errors.push("FI-Bkgd-Blank value must be a number. Found: " + d['FI-Bkgd-Blank']);
                    }

                    // validate CV is present and a number w/ opt. trailing '%'
                    if (typeof(d['CV']) == "undefined") {
                        $scope.csv_errors.push("CV field is required");
                    } else {
                        // need to strip the trailing % if present
                        cv_result = cv_pattern.exec(d['CV']);
                        if (cv_result == null) {
                            $scope.csv_errors.push("CV value must be a percentage. Found: " + d['CV']);
                        } else if (isNaN(cv_result[0])) {
                            $scope.csv_errors.push("CV value must be a percentage. Found: " + d['CV']);
                        }
                    }
                });

                // Now check all our validation data

                // only one cohort should be present
                if (distinct_cohorts.length > 1) {
                    $scope.csv_errors.push("Multiple cohorts found in CSV file. Data can only be uploaded for one cohort at a time");
                }

                // cohort must match current cohort
                if (distinct_cohorts[0] != $scope.current_cohort.name) {
                    $scope.csv_errors.push("Cohort in CSV file doesn't match this cohort");
                }

                // only one network should be present and should match the
                // cohort's network
                if (distinct_networks.length > 1) {
                    $scope.csv_errors.push("Multiple networks found in CSV file. Data can only be uploaded for one network at a time");
                }

                // cohort must match current cohort
                if (distinct_networks[0] != $scope.current_cohort.network_name) {
                    $scope.csv_errors.push("Network in CSV file doesn't match this cohort's network");
                }

                // determine if any new notebooks are present
                distinct_notebooks_tmp.forEach(function (n) {
                    var new_nb = false;
                    if ($scope.notebooks.indexOf(n) == -1) {
                        new_nb = true;
                    }
                    $scope.distinct_notebooks.push(
                        {
                            name: n,
                            new: new_nb
                        }
                    );
                });
            }
        }
    ]
);<|endoftext|>


<commit_before>// gulp libs
var gulp = require('gulp');
var release = require('gulp-github-release');
var gulpUtil = require('gulp-util');
var tag = new Date().toISOString().replace(/T.+$/, '').replace(/-/g, '.');

// js concat & minify
gulp.task('release', function () {
	gulp.src('./dist/deploy.zip')
		.pipe(release({
			//token: token,                     // or you can set an env var called GITHUB_TOKEN instead
			//owner: owner,                    	// if missing, it will be extracted from manifest (the repository.url field)
			//repo: 'publish-release',          // if missing, it will be extracted from manifest (the repository.url field)
			tag: 'release-' + tag,              // if missing, the version will be extracted from manifest and prepended by a 'v'
			name: 'publish release ' + tag,     // if missing, it will be the same as the tag
			notes: 'very good!',                // if missing it will be left undefined
			draft: false,                       // if missing it's false
			prerelease: false,                  // if missing it's false
			manifest: require('./package.json') // package.json from which default values will be extracted if they're missing
		}));
});

gulp.task('default', function () {});
<commit_msg>tag tests<commit_after>// gulp libs
var gulp = require('gulp');
var release = require('gulp-github-release');
var gulpUtil = require('gulp-util');
//var tag = new Date().toISOString().replace(/T.+$/, '').replace(/-/g, '.');
var tag = '1.0.0';

// js concat & minify
gulp.task('release', function () {
	gulp.src('./dist/deploy.zip')
		.pipe(release({
			//token: token,                     // or you can set an env var called GITHUB_TOKEN instead
			//owner: owner,                    	// if missing, it will be extracted from manifest (the repository.url field)
			//repo: 'publish-release',          // if missing, it will be extracted from manifest (the repository.url field)
			tag: 'release-' + tag,              // if missing, the version will be extracted from manifest and prepended by a 'v'
			name: 'publish release ' + tag,     // if missing, it will be the same as the tag
			notes: 'very good!',                // if missing it will be left undefined
			draft: false,                       // if missing it's false
			prerelease: false,                  // if missing it's false
			manifest: require('./package.json') // package.json from which default values will be extracted if they're missing
		}));
});

gulp.task('default', function () {});
<|endoftext|>


<commit_before>

/* Impression de l'ajout ou du retrait d'un ami dans la liste du menu */

function new_friend_list(ev) {
    var elem = ev.detail;
    var name = elem.name;
    var id = elem.id;
    var matrice = document.getElementById('fl_matrice');
    var nplace = matrice.cloneNode(true);
    var spans = nplace.getElementsByTagName('span');

    nplace.id = "li_" + name;
    spans[0].innerHTML = name;
    matrice.parentNode.appendChild(nplace);
    show(nplace);
    update_friends_place_list(id, name, true);
}

function old_friend_list(ev) {
    var elem = ev.detail;
    var name = elem.name;

    var node = document.getElementById("li_" + name);
    node.parentNode.removeChild(node);
}

/*========== GET SEEK FRIEND =============*/

var xmlhttp = getXhr();

xmlhttp.onreadystatechange = function() {
    var response;
    var jsonResponse;

    if (xmlhttp.readyState != 4 ||  xmlhttp.status != 200) {
        return;
    }

    response = xmlhttp.responseText;

    try {
        jsonResponse = JSON.parse(response);
    } catch(e) {
        hide(document.getElementById('seek_running'));
        show(document.getElementById('seek_error'));
        return;
    }

    if (typeof(jsonResponse.error) == "string") {
        hide(document.getElementById('seek_running'));
        document.getElementById('seek_error_msg').innerHTML = jsonResponse.error;
        show(document.getElementById('seek_error'));
        return;
    }

    document.getElementById('seek_search').innerHTML = jsonResponse.recherche;
    document.getElementById('seek_name').innerHTML = jsonResponse.name;
    document.getElementById('seek_mail').innerHTML = jsonResponse.mail;
    hide(document.getElementById('seek_running'));
    show(document.getElementById('seek_result'));
}

function seek_friend_action() {
    var seek = document.getElementById('seek_friend_input').value;

    hide(document.getElementById('seek_result'));
    hide(document.getElementById('seek_error'));
    show(document.getElementById('seek_running'));
    xmlhttp.open("GET", "friend/search/" + seek, true);
//    xmlhttp.open("GET", "lookforfriend/" + seek, true);
    xmlhttp.send();
}

function insert_friend(friend) {
    friends.add(friend.id, friend);
}

/*========== GET FRIEND LIST =============*/

var xmlhttpfl = getXhr();

xmlhttpfl.onreadystatechange = function() {
    var response;
    var jsonResponse;

    if (xmlhttpfl.readyState != 4 ||  xmlhttpfl.status != 200) {
        return;
    }

    response = xmlhttpfl.responseText;

    try {
        jsonResponse = JSON.parse(response);
    } catch(e) {
        hide(document.getElementById('fl_running'));
        show(document.getElementById('fl_error'));
        return;
    }

    if (typeof(jsonResponse.error) == "string") {
        hide(document.getElementById('fl_running'));
        document.getElementById('fl_error_msg').innerHTML = jsonResponse.error;
        show(document.getElementById('fl_error'));
        return;
    }

    var matrice = document.getElementById('fl_matrice');

    hide(matrice);

    for (var e in jsonResponse) {
        insert_friend(jsonResponse[e]);
        update_friends_place_list(e, jsonResponse[e]);
    }

    hide(document.getElementById('fl_running'));
    show(document.getElementById('fl_result'));
}

function update_friend_list() {
    show(document.getElementById('fl_running'));
    xmlhttpfl.open("GET", "friend/", true);
    xmlhttpfl.send();
}

/*========== REMOVE FRIEND =============*/

var xmlhttprf = getXhr();

xmlhttprf.onreadystatechange = function() {
    var response;
    var jsonResponse;

    if (xmlhttprf.readyState != 4 ||  xmlhttprf.status != 200) {
        return;
    }

    response = xmlhttprf.responseText;

    try {
        jsonResponse = JSON.parse(response);
    } catch(e) {
        return;
    }

    if (typeof(jsonResponse.error) == "string") {
        return;
    }

    remove_friend(jsonResponse.id);
}

function remove_friend(id) {
    friends.remove(id);
}

function send_rem_friend(friend) {
    xmlhttprf.open("DELETE", "friend/" + friend, true);
    xmlhttprf.send();
}

function del_friend(name) {
    if (name == "") {
        return;
    }

    send_rem_friend(name);
}

function rem_friend(e) {
    var name = "";
    var str = e.target.parentNode.parentNode.id;

    name = str.substr(str.indexOf('_') + 1, str.length);

    del_friend(name)
}

/*========== ADD FRIEND =============*/

var xmlhttpaf = getXhr();

xmlhttpaf.onreadystatechange = function() {
    var response;
    var jsonResponse;

    if (xmlhttpaf.readyState != 4 ||  xmlhttpaf.status != 200) {
        return;
    }

    response = xmlhttpaf.responseText;

    try {
        jsonResponse = JSON.parse(response);
    } catch(e) {
        return;
    }

    if (typeof(jsonResponse.error) == "string") {
        return;
    }

    insert_friend(jsonResponse);
}

function send_add_friend(friend) {
    xmlhttpaf.open("POST", "friend/" + friend, true);
    xmlhttpaf.send();
}

function add_friend() {
    var friend = document.getElementById('seek_name').innerHTML;
    send_add_friend(friend);
}

/*========== GET FRIEND PLACE LIST =============*/

/* Gestion Liste locale */

/* Gestion Ajax */
function req_before_friends_place_list() {
}

function local_err_friends_place_list () {
}

function req_return_friends_place_list(jsonResponse) {

    if (jsonResponse == null) {
        return;
    }

    if (typeof(jsonResponse.error) == "string") {
        return;
    }

    var matrice = document.getElementById('fpl_matrice');

    hide(matrice);

    for (var e in jsonResponse) {
        if (jsonResponse[e].places != null) {
            friendsplaces.merge(jsonResponse[e].places);
        }
    }

    if (placefriendqueue != undefined) {
        placefriendqueue.run();
    }
}

function req_end_friends_place_list(queue) {
}

var req_friends_place_list = new Request(
        req_before_friends_place_list,
        null,
        local_err_friends_place_list,
        req_return_friends_place_list,
        req_end_friends_place_list
        );

function queue_friend_place(params) {
    req_friends_place_list.send(params.method, params.query, true);
}

var placefriendqueue = undefined;

function update_friends_place_list(id, name, prio) {
    if (placefriendqueue == undefined) {
        placefriendqueue = new Queue();
    }

    console.log("TEST 1");
    if (prio == true) {
    console.log("TEST 2");
        placefriendqueue.addFirst(queue_friend_place, {method:"GET", query:"place/friend/" + id + "/" + name});
    } else {
    console.log("TEST 3");
        placefriendqueue.add(queue_friend_place, {method:"GET", query:"place/friend/" + id + "/" + name});
    }
}

<commit_msg>retrait console log<commit_after>

/* Impression de l'ajout ou du retrait d'un ami dans la liste du menu */

function new_friend_list(ev) {
    var elem = ev.detail;
    var name = elem.name;
    var id = elem.id;
    var matrice = document.getElementById('fl_matrice');
    var nplace = matrice.cloneNode(true);
    var spans = nplace.getElementsByTagName('span');

    nplace.id = "li_" + name;
    spans[0].innerHTML = name;
    matrice.parentNode.appendChild(nplace);
    show(nplace);
    update_friends_place_list(id, name, true);
}

function old_friend_list(ev) {
    var elem = ev.detail;
    var name = elem.name;

    var node = document.getElementById("li_" + name);
    node.parentNode.removeChild(node);
}

/*========== GET SEEK FRIEND =============*/

var xmlhttp = getXhr();

xmlhttp.onreadystatechange = function() {
    var response;
    var jsonResponse;

    if (xmlhttp.readyState != 4 ||  xmlhttp.status != 200) {
        return;
    }

    response = xmlhttp.responseText;

    try {
        jsonResponse = JSON.parse(response);
    } catch(e) {
        hide(document.getElementById('seek_running'));
        show(document.getElementById('seek_error'));
        return;
    }

    if (typeof(jsonResponse.error) == "string") {
        hide(document.getElementById('seek_running'));
        document.getElementById('seek_error_msg').innerHTML = jsonResponse.error;
        show(document.getElementById('seek_error'));
        return;
    }

    document.getElementById('seek_search').innerHTML = jsonResponse.recherche;
    document.getElementById('seek_name').innerHTML = jsonResponse.name;
    document.getElementById('seek_mail').innerHTML = jsonResponse.mail;
    hide(document.getElementById('seek_running'));
    show(document.getElementById('seek_result'));
}

function seek_friend_action() {
    var seek = document.getElementById('seek_friend_input').value;

    hide(document.getElementById('seek_result'));
    hide(document.getElementById('seek_error'));
    show(document.getElementById('seek_running'));
    xmlhttp.open("GET", "friend/search/" + seek, true);
//    xmlhttp.open("GET", "lookforfriend/" + seek, true);
    xmlhttp.send();
}

function insert_friend(friend) {
    friends.add(friend.id, friend);
}

/*========== GET FRIEND LIST =============*/

var xmlhttpfl = getXhr();

xmlhttpfl.onreadystatechange = function() {
    var response;
    var jsonResponse;

    if (xmlhttpfl.readyState != 4 ||  xmlhttpfl.status != 200) {
        return;
    }

    response = xmlhttpfl.responseText;

    try {
        jsonResponse = JSON.parse(response);
    } catch(e) {
        hide(document.getElementById('fl_running'));
        show(document.getElementById('fl_error'));
        return;
    }

    if (typeof(jsonResponse.error) == "string") {
        hide(document.getElementById('fl_running'));
        document.getElementById('fl_error_msg').innerHTML = jsonResponse.error;
        show(document.getElementById('fl_error'));
        return;
    }

    var matrice = document.getElementById('fl_matrice');

    hide(matrice);

    for (var e in jsonResponse) {
        insert_friend(jsonResponse[e]);
        update_friends_place_list(e, jsonResponse[e]);
    }

    hide(document.getElementById('fl_running'));
    show(document.getElementById('fl_result'));
}

function update_friend_list() {
    show(document.getElementById('fl_running'));
    xmlhttpfl.open("GET", "friend/", true);
    xmlhttpfl.send();
}

/*========== REMOVE FRIEND =============*/

var xmlhttprf = getXhr();

xmlhttprf.onreadystatechange = function() {
    var response;
    var jsonResponse;

    if (xmlhttprf.readyState != 4 ||  xmlhttprf.status != 200) {
        return;
    }

    response = xmlhttprf.responseText;

    try {
        jsonResponse = JSON.parse(response);
    } catch(e) {
        return;
    }

    if (typeof(jsonResponse.error) == "string") {
        return;
    }

    remove_friend(jsonResponse.id);
}

function remove_friend(id) {
    friends.remove(id);
}

function send_rem_friend(friend) {
    xmlhttprf.open("DELETE", "friend/" + friend, true);
    xmlhttprf.send();
}

function del_friend(name) {
    if (name == "") {
        return;
    }

    send_rem_friend(name);
}

function rem_friend(e) {
    var name = "";
    var str = e.target.parentNode.parentNode.id;

    name = str.substr(str.indexOf('_') + 1, str.length);

    del_friend(name)
}

/*========== ADD FRIEND =============*/

var xmlhttpaf = getXhr();

xmlhttpaf.onreadystatechange = function() {
    var response;
    var jsonResponse;

    if (xmlhttpaf.readyState != 4 ||  xmlhttpaf.status != 200) {
        return;
    }

    response = xmlhttpaf.responseText;

    try {
        jsonResponse = JSON.parse(response);
    } catch(e) {
        return;
    }

    if (typeof(jsonResponse.error) == "string") {
        return;
    }

    insert_friend(jsonResponse);
}

function send_add_friend(friend) {
    xmlhttpaf.open("POST", "friend/" + friend, true);
    xmlhttpaf.send();
}

function add_friend() {
    var friend = document.getElementById('seek_name').innerHTML;
    send_add_friend(friend);
}

/*========== GET FRIEND PLACE LIST =============*/

/* Gestion Liste locale */

/* Gestion Ajax */
function req_before_friends_place_list() {
}

function local_err_friends_place_list () {
}

function req_return_friends_place_list(jsonResponse) {

    if (jsonResponse == null) {
        return;
    }

    if (typeof(jsonResponse.error) == "string") {
        return;
    }

    var matrice = document.getElementById('fpl_matrice');

    hide(matrice);

    for (var e in jsonResponse) {
        if (jsonResponse[e].places != null) {
            friendsplaces.merge(jsonResponse[e].places);
        }
    }

    if (placefriendqueue != undefined) {
        placefriendqueue.run();
    }
}

function req_end_friends_place_list(queue) {
}

var req_friends_place_list = new Request(
        req_before_friends_place_list,
        null,
        local_err_friends_place_list,
        req_return_friends_place_list,
        req_end_friends_place_list
        );

function queue_friend_place(params) {
    req_friends_place_list.send(params.method, params.query, true);
}

var placefriendqueue = undefined;

function update_friends_place_list(id, name, prio) {
    if (placefriendqueue == undefined) {
        placefriendqueue = new Queue();
    }

    if (prio == true) {
        placefriendqueue.addFirst(queue_friend_place, {method:"GET", query:"place/friend/" + id + "/" + name});
    } else {
        placefriendqueue.add(queue_friend_place, {method:"GET", query:"place/friend/" + id + "/" + name});
    }
}

<|endoftext|>


<commit_before>var container = document.querySelector('#chessReplayApp');
var chessBoard = document.createElement('table');
var pieceMap = {};

const chessBoardTileLength = 8;
const columnLetters = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'];
const colors = ['white', 'black'];
const pieces = ['King', 'Queen', 'Bishop', 'Knight', 'Rook', 'Pawn']

var rowIndex = 0;
var columnIndex  = 0;

for(rowIndex; rowIndex < chessBoardTileLength; ++rowIndex){
    var chessBoardRow = chessBoard.insertRow(rowIndex);
    chessBoardRow.id = chessBoardTileLength - rowIndex;
    for(columnIndex = 0; columnIndex < chessBoardTileLength; ++columnIndex){
        var chessBoardCell = chessBoardRow.insertCell(columnIndex);
        chessBoardCell.id = columnLetters [columnIndex] + chessBoardRow.id;
    }
}

var colorIndex = 0;
var pieceIndex = 0;
for(colorIndex; colorIndex < colors.length; ++colorIndex){
    for(pieceIndex = 0; pieceIndex < pieces.length; ++pieceIndex){
        pieceMap[colors[colorIndex] + pieces[pieceIndex]] = {};
    }
}
console.log(JSON.stringify(pieceMap));

var whiteKing = document.createElement('div');
whiteKing.classList.add('piece', 'whiteKing');
var whiteQueen = document.createElement('div');
whiteQueen.classList.add('piece', 'whiteQueen');
var whiteBishop = document.createElement('div');
whiteBishop.classList.add('piece', 'whiteBishop');
var whiteKnight = document.createElement('div');
whiteKnight.classList.add('piece', 'whiteKnight');
var whiteRook = document.createElement('div');
whiteRook.classList.add('piece', 'whiteRook');
var whitePawn = document.createElement('div');
whitePawn.classList.add('piece', 'whitePawn');

var blackKing = document.createElement('div');
blackKing.classList.add('piece', 'blackKing');
var blackQueen = document.createElement('div');
blackQueen.classList.add('piece', 'blackQueen');
var blackBishop = document.createElement('div');
blackBishop.classList.add('piece', 'blackBishop');
var blackKnight = document.createElement('div');
blackKnight.classList.add('piece', 'blackKnight');
var blackRook = document.createElement('div');
blackRook.classList.add('piece', 'blackRook');
var blackPawn = document.createElement('div');
blackPawn.classList.add('piece', 'blackPawn');

container.appendChild(chessBoard);
container.appendChild(whiteKing);
<commit_msg>added function to build pieces<commit_after>var container = document.querySelector('#chessReplayApp');
var chessBoard = document.createElement('table');
var pieceMap = {};

const chessBoardTileLength = 8;
const columnLetters = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'];
const colors = ['white', 'black'];
const pieces = ['King', 'Queen', 'Bishop', 'Knight', 'Rook', 'Pawn']

var rowIndex = 0;
var columnIndex  = 0;

for(rowIndex; rowIndex < chessBoardTileLength; ++rowIndex){
    var chessBoardRow = chessBoard.insertRow(rowIndex);
    chessBoardRow.id = chessBoardTileLength - rowIndex;
    for(columnIndex = 0; columnIndex < chessBoardTileLength; ++columnIndex){
        var chessBoardCell = chessBoardRow.insertCell(columnIndex);
        chessBoardCell.id = columnLetters [columnIndex] + chessBoardRow.id;
    }
}

var colorIndex = 0;
var pieceIndex = 0;
for(colorIndex; colorIndex < colors.length; ++colorIndex){
    for(pieceIndex = 0; pieceIndex < pieces.length; ++pieceIndex){
        pieceMap[colors[colorIndex] + pieces[pieceIndex]] = {};
    }
}
console.log(JSON.stringify(pieceMap));
function buildPiece(name){
    var piece = document.createElement('div');
    piece.classList.add('piece', name);
    return piece;
}

for(var name in pieceMap){
    container.appendChild(buildPiece(name));
}
container.appendChild(chessBoard);<|endoftext|>


<commit_before>function Chronoshift (verboseLogs = false, verboseTime = false, writeLogs = true) {
  let self = this;
  this.version = 0.5;
  this.tasks = {};
  this.logs = [];
  this.verboseLogs = false;
  this.verboseTime = false;
  this.writeLogs = true;
  this.controlCount = 0;
  this.cpOpened = false;

  //Define type of logging
  //verboseLogs - print or not print logs in console,
  //verboseTime - add or not add timestamp
  //writeLogs - store or not store logs in inner storage (this.logs)
  this.setLogging = function(verboseLogs, verboseTime = this.verboseTime, writeLogs = this.writeLogs){
    if (verboseLogs == undefined)
      return;
    this.verboseLogs = !!verboseLogs;
    this.verboseTime = !!verboseTime;
    this.writeLogs = !!writeLogs;
  };

  //Logging events with settings from setLogging options
  this.log = function(){
    let now = new Date();
    let nowAsString = now.toLocaleString() + "." + now.getMilliseconds();
    if (this.verboseLogs){
      if (this.verboseTime){
        console.log("[" + nowAsString + "] \r");
      }
    console.log.apply(null,arguments);
    }
    let logData = [];
    let i = 0;
    while(arguments[i]){
      logData[i] = arguments[i];
      i++;
    }
    logData = logData.join("");
    if (this.writeLogs)
      this.logs.push({"log": logData, "time": nowAsString, "timestamp": now.getTime()});
  };

  //Print logs in console as a table from start to end
  this.showLogs = function(start, end){
    let requiredSlice = this.logs;
    if ( (start || end)){
      start = +start || 0;
      end = +end || (this.logs.length);
      if (!isNaN(start+end))
        requiredSlice = this.logs.slice(start, end);
    }
    console.table(requiredSlice);
  };

  //Print tasks in console as a table from start to end OR some set of names
  this.showTasks = function(startOrSet, end){
    let requiredSlice = this.tasks;
    if ( (startOrSet || end) && !startOrSet.slice){
      let start = startOrSet;
      start = +start || 0;
      end = +end || (this.tasks.length);
      if (!isNaN(start+end))
        requiredSlice = this.tasks.slice(start, end);
    }
    else if (startOrSet && !end && startOrSet.forEach){
      let set = startOrSet;
      requiredSlice = [];
      set.forEach(function(e, i, a){
        requiredSlice.push(self.tasks[e]);
      });
    }
    console.table(requiredSlice);

  }

  //Run function [handler] with [delay]ms delay, if [repeat] then repeat [handler] every [delay]ms
  //This function will be saved as task [name || random_string] with description [description]
  //[name] must be valid js variable name or it will be transliterated into such name
  //Only necessary parameters are "handler" and "delay"
  this.run = function(handler, delay, repeat, name, description){
    this.log("Creating task: ", JSON.stringify( arguments));
    if(!handler)
      return false;
    let pid = 0;
    delay = delay? +delay : 0;
    delay = ( typeof delay == "number" && !isNaN(delay) )? delay: 0;
    name = typeof name == "string"?
      //replace with _ all not valid in variable symbols
      name.replace(/([^a-zA-Z0-9_$])/g, "_")
        //then replace first symbol with _ if this sybol is digit
        .replace(/^\d/, 'd'):
      //generate random name if argument name is not a string
      "task_"+Math.random().toString(32).substr(2);
    //check for existence of this name in task
    //yes, this is possible, even if chanse less then 1:1 000 000
    while (this.tasks[name])
        name = "task_"+Math.random().toString(32).substr(2);
    description = description? "" + description : "No description";
    if (repeat){
      pid = setInterval(()=>{handler();this.log("Task executed:", name);}, delay);
    }
    else{
      pid = setTimeout(()=> {handler();this.log("Task executed:", name);this.stop(name); }, delay);
    };
    let at = new Date(Date.now()+delay);
    at = at.toLocaleString().replace(/(T|Z)/gi, " ");
    console.log(at);
    this.tasks[name] = {
      "pid": pid,
      "timeout":delay,
      "at": at,
      "description": description,
      "repeat": repeat,
      "name": name,
      "handler": handler
    };
    this.log("Added a task ", name, " with timeout ", delay, repeat? " looped" : "");
    return pid;
  };

  //Run function [handler] exactly at [at]; if [at] not a full date it will be updated with suggestions,
  //For example, 23-12-19 -> 2023, 19 december, 00:00:00;
  //22:43 -> today at 22:43:00, but if too late to do so then it will be tomorow at 22:43:00
  //You can use ms in date format, but they will be ignored
  //Timestamp also acceptable
  //This task will be saved as task [name || random_string] with description [description]
  //[name] must be valid js variable name or it will be transliterated into such name
  //Only necessary parameters are "handler" and "at"
  this.runAt = function(handler, at, name, description){
    name = typeof name == "string"? name.replace(/ /g, "_"): "task_"+Math.random().toString(32).substr(2);
    while (this.tasks[name])
      name = "task_"+Math.random().toString(32).substr(2);
    let now = new Date(), then = new Date();

    if (typeof at == "string"){
      let patterns = [
        /^\d{2,4}-\d{1,2}-\d{1,2} \d{1,2}:\d{1,2}:\d{1,2}.\d{1,3}$/,
        /^\d{2,4}-\d{1,2}-\d{1,2} \d{1,2}:\d{1,2}:\d{1,2}$/,
        /^\d{2,4}-\d{1,2}-\d{1,2}$/,
        /^\d{1,2}:\d{1,2}:\d{1,2}.\d{1,3}$/,
        /^\d{1,2}:\d{1,2}:\d{1,2}$/,
        /^\d{1,2}:\d{1,2}$/

      ];
      let inputCase = -1;
      patterns.forEach(function(e, i, a){
        if(inputCase != -1)
        return;
        if (e.test(at)){
          inputCase = i;
        };
      });
      if (inputCase<0){
        this.console.log("Function runAt aborted. Wrong date/time string: ", at);
        return false;
      }
      let atString = at.match(patterns[inputCase])[0];
      switch (inputCase) {
        case 0:
        case 1:
        case 2:
          atStringYear = atString.split("-")[0];
          if (atStringYear.length == 2)
            atString = "20" + atString;
        break;
        case 3:
        case 4:
        case 5:
          atString = "" + now.getFullYear() + "-" + (now.getMonth() + 1) + "-" + now.getDate() + " " + atString;
        default:
      }
      then = new Date(atString);
      if (then < now && inputCase>2) {
        then = new Date(then.getTime() + 24*60*60*1000);
      }
    }
    else if (typeof at == "number" && !isNaN(at))
      then = new Date(at);
    else{
      this.log("Invalid \"at\" argument in call runAt!");
      return false;
    }

    let delay = then - now;
    if (delay<0){
      this.log("Function can not be run at ", then, " nj");
      return false;
    }
    this.run(handler, delay, false, name, description);
    return true;
  };

  //Run handler of task by name or pid
  this.runTask = function(id){
    let name = typeof id == "number"? this.getTaskName(id) : id;
    if ( (!name || !this.tasks[name]))
      return false;
    this.log("Forced run task \"", name, "\" with pid ", this.tasks[name].pid);
    this.tasks[name].handler();
    return true;
  };

  this.getTaskName = function(pid){
    if (typeof pid != "number")
      return false;
    for(x in this.tasks){
      if (this.tasks[x].pid == pid){
        return x;
      }
    }
    return false;
  }

  //Remove task by task name in cronoshift or process id from list
  this.stop = function (id) {
    this.log("Stoping task: ", id);

    let stopTask = (id, repeat) => {
      if (repeat)
        clearInterval(id);
      else
        clearTimeout(id);
    }
    let found = false;
    let name = false;
    try{
      if (typeof id == "number"){
        name = this.getTaskName(id);
        if (!name){
          this.log("---Not found task with pid ", id, "!");
          return false;
        }
        this.log("Task with pid ", id, " found");
      }
      else if (typeof id == "string") {
        if (!this.tasks[id]){
          this.log("---Task ", id), " not found!";
          return false;
        }
        this.log("Task ", id, " found");
      }
      let finalId = name? name : id;
      stopTask(this.tasks[finalId].pid, this.tasks[finalId].repeat);
      delete this.tasks[finalId];
    }
    catch (e){
      this.log("---Problems when trying to stop ", id, " :", e);
      return false;
    }
    this.log("Stoping task ", id, " finished");
    return true;
  };

  this.openControlPanel = function(){
    self.cpOpened = true;
    console.log("CP opened");
  };

  this.closeControlPanel = function(){
    if (!self.cpOpened)
      return
    self.cpOpened = false;
    console.log("CP closed");
  };

  //Watch keyup and waiting for Ctr Ctrl Ctrl to open control panel
  window.addEventListener("keyup", function(e){
    if (e.key == "Control")
      self.controlCount++;
    else if (e.key == "Escape")
      self.closeControlPanel();
    if (self.controlCount>=3){
      self.controlCount = 0;
      self.openControlPanel();
    }
  });

  this.verboseLogs = verboseLogs;
  this.verboseTime = verboseTime;
  this.writeLogs = writeLogs;
  this.run(()=>{console.log("Example function executed");}, 42000000, false, "example", "This is a sample task. It will do nothing.");

}
<commit_msg>Waypoint<commit_after>function Chronoshift (verboseLogs = false, verboseTime = false, writeLogs = true) {
  let self = this;
  window._chronoshift = this;
  this.version = 0.5;
  this.tasks = {};
  this.logs = [];
  this.verboseLogs = false;
  this.verboseTime = false;
  this.writeLogs = true;
  this.controlCount = 0;
  this.cpOpened = false;

  //Define type of logging
  //verboseLogs - print or not print logs in console,
  //verboseTime - add or not add timestamp
  //writeLogs - store or not store logs in inner storage (this.logs)
  this.setLogging = function(verboseLogs, verboseTime = this.verboseTime, writeLogs = this.writeLogs){
    if (verboseLogs == undefined)
      return;
    this.verboseLogs = !!verboseLogs;
    this.verboseTime = !!verboseTime;
    this.writeLogs = !!writeLogs;
  };

  //Logging events with settings from setLogging options
  this.log = function(){
    let now = new Date();
    let nowAsString = now.toLocaleString() + "." + now.getMilliseconds();
    if (this.verboseLogs){
      if (this.verboseTime){
        console.log("[" + nowAsString + "] \r");
      }
    console.log.apply(null,arguments);
    }
    let logData = [];
    let i = 0;
    while(arguments[i]){
      logData[i] = arguments[i];
      i++;
    }
    logData = logData.join("");
    if (this.writeLogs)
      this.logs.push({"log": logData, "time": nowAsString, "timestamp": now.getTime()});
  };

  //Print logs in console as a table from start to end
  this.showLogs = function(start, end){
    let requiredSlice = this.logs;
    if ( (start || end)){
      start = +start || 0;
      end = +end || (this.logs.length);
      if (!isNaN(start+end))
        requiredSlice = this.logs.slice(start, end);
    }
    console.table(requiredSlice);
  };

  //Print tasks in console as a table from start to end OR some set of names
  this.showTasks = function(startOrSet, end){
    let requiredSlice = this.tasks;
    if ( (startOrSet || end) && !startOrSet.slice){
      let start = startOrSet;
      start = +start || 0;
      end = +end || (this.tasks.length);
      if (!isNaN(start+end))
        requiredSlice = this.tasks.slice(start, end);
    }
    else if (startOrSet && !end && startOrSet.forEach){
      let set = startOrSet;
      requiredSlice = [];
      set.forEach(function(e, i, a){
        requiredSlice.push(self.tasks[e]);
      });
    }
    console.table(requiredSlice);

  }

  //Run function [handler] with [delay]ms delay, if [repeat] then repeat [handler] every [delay]ms
  //This function will be saved as task [name || random_string] with description [description]
  //[name] must be valid js variable name or it will be transliterated into such name
  //Only necessary parameters are "handler" and "delay"
  this.run = function(handler, delay, repeat, name, description){
    this.log("Creating task: ", JSON.stringify( arguments));
    if(!handler)
      return false;
    let pid = 0;
    delay = delay? +delay : 0;
    delay = ( typeof delay == "number" && !isNaN(delay) )? delay: 0;
    name = typeof name == "string"?
      //replace with _ all not valid in variable symbols
      name.replace(/([^a-zA-Z0-9_$])/g, "_")
        //then replace first symbol with _ if this sybol is digit
        .replace(/^\d/, 'd'):
      //generate random name if argument name is not a string
      "task_"+Math.random().toString(32).substr(2);
    //check for existence of this name in task
    //yes, this is possible, even if chanse less then 1:1 000 000
    while (this.tasks[name])
        name = "task_"+Math.random().toString(32).substr(2);
    description = description? "" + description : "No description";
    if (repeat){
      pid = setInterval(()=>{handler();this.log("Task executed:", name);}, delay);
    }
    else{
      pid = setTimeout(()=> {handler();this.log("Task executed:", name);this.stop(name); }, delay);
    };
    let at = new Date(Date.now()+delay);
    at = at.toLocaleString().replace(/(T|Z)/gi, " ");
    console.log(at);
    this.tasks[name] = {
      "pid": pid,
      "timeout":delay,
      "at": at,
      "description": description,
      "repeat": repeat,
      "name": name,
      "handler": handler
    };
    this.log("Added a task ", name, " with timeout ", delay, repeat? " looped" : "");
    return pid;
  };

  //Run function [handler] exactly at [at]; if [at] not a full date it will be updated with suggestions,
  //For example, 23-12-19 -> 2023, 19 december, 00:00:00;
  //22:43 -> today at 22:43:00, but if too late to do so then it will be tomorow at 22:43:00
  //You can use ms in date format, but they will be ignored
  //Timestamp also acceptable
  //This task will be saved as task [name || random_string] with description [description]
  //[name] must be valid js variable name or it will be transliterated into such name
  //Only necessary parameters are "handler" and "at"
  this.runAt = function(handler, at, name, description){
    name = typeof name == "string"? name.replace(/ /g, "_"): "task_"+Math.random().toString(32).substr(2);
    while (this.tasks[name])
      name = "task_"+Math.random().toString(32).substr(2);
    let now = new Date(), then = new Date();

    if (typeof at == "string"){
      let patterns = [
        /^\d{2,4}-\d{1,2}-\d{1,2} \d{1,2}:\d{1,2}:\d{1,2}.\d{1,3}$/,
        /^\d{2,4}-\d{1,2}-\d{1,2} \d{1,2}:\d{1,2}:\d{1,2}$/,
        /^\d{2,4}-\d{1,2}-\d{1,2}$/,
        /^\d{1,2}:\d{1,2}:\d{1,2}.\d{1,3}$/,
        /^\d{1,2}:\d{1,2}:\d{1,2}$/,
        /^\d{1,2}:\d{1,2}$/

      ];
      let inputCase = -1;
      patterns.forEach(function(e, i, a){
        if(inputCase != -1)
        return;
        if (e.test(at)){
          inputCase = i;
        };
      });
      if (inputCase<0){
        this.console.log("Function runAt aborted. Wrong date/time string: ", at);
        return false;
      }
      let atString = at.match(patterns[inputCase])[0];
      switch (inputCase) {
        case 0:
        case 1:
        case 2:
          atStringYear = atString.split("-")[0];
          if (atStringYear.length == 2)
            atString = "20" + atString;
        break;
        case 3:
        case 4:
        case 5:
          atString = "" + now.getFullYear() + "-" + (now.getMonth() + 1) + "-" + now.getDate() + " " + atString;
        default:
      }
      then = new Date(atString);
      if (then < now && inputCase>2) {
        then = new Date(then.getTime() + 24*60*60*1000);
      }
    }
    else if (typeof at == "number" && !isNaN(at))
      then = new Date(at);
    else{
      this.log("Invalid \"at\" argument in call runAt!");
      return false;
    }

    let delay = then - now;
    if (delay<0){
      this.log("Function can not be run at ", then, " nj");
      return false;
    }
    this.run(handler, delay, false, name, description);
    return true;
  };

  //Run handler of task by name or pid
  this.runTask = function(id){
    let name = typeof id == "number"? this.getTaskName(id) : id;
    if ( (!name || !this.tasks[name]))
      return false;
    this.log("Forced run task \"", name, "\" with pid ", this.tasks[name].pid);
    this.tasks[name].handler();
    return true;
  };

  this.getTaskName = function(pid){
    if (typeof pid != "number")
      return false;
    for(x in this.tasks){
      if (this.tasks[x].pid == pid){
        return x;
      }
    }
    return false;
  }

  //Remove task by task name in cronoshift or process id from list
  this.stop = function (id) {
    this.log("Stoping task: ", id);

    let stopTask = (id, repeat) => {
      if (repeat)
        clearInterval(id);
      else
        clearTimeout(id);
    }
    let found = false;
    let name = false;
    try{
      if (typeof id == "number"){
        name = this.getTaskName(id);
        if (!name){
          this.log("---Not found task with pid ", id, "!");
          return false;
        }
        this.log("Task with pid ", id, " found");
      }
      else if (typeof id == "string") {
        if (!this.tasks[id]){
          this.log("---Task ", id), " not found!";
          return false;
        }
        this.log("Task ", id, " found");
      }
      let finalId = name? name : id;
      stopTask(this.tasks[finalId].pid, this.tasks[finalId].repeat);
      delete this.tasks[finalId];
    }
    catch (e){
      this.log("---Problems when trying to stop ", id, " :", e);
      return false;
    }
    this.log("Stoping task ", id, " finished");
    return true;
  };

  //Code with long function names, especially with methods as arguments of method
  //hard to read, so here created some shortcuts

  this.openControlPanel = function(){
    if (self.cpOpened){
      return false;
    }

    let eCreate = function(e) {
          return document.createElement(e);
        },

        eFind = function(e) {
          return document.querySelector(e);
        },

        ePush = function(element, children){
          children.forEach(function(e, i, a){
            element.appendChild(e)
          });
        }

        appendChain = function(x) {
          this.appendChild(x);
          return this;
        };

        //Functions for create table row and cell
        createStrip = function(){
          let strip = eCreate('div');
          strip.className = 'strip'
          strip.appendChain = appendChain;
          return strip;
        };

        createCell = function(width, content, align){
          align = align? align : "center";
          let cell = eCreate('div');
          cell.className = 'cell';
          cell.style.width = width;
          cell.style.textAlign = align;
          if (typeof content == "object")
            cell.appendChild(content);
          else
            cell.innerHTML = '' + content;
          return cell;

        };

    //Styling for control panel.
    let style = eCreate('style');
    style.innerHTML = `
  .cs-control{
    border-radius: 3px;
    background-color: ivory;
    border: 1px solid black;
    width: 90%;
    left:5%;
    height:90%;
    top:5%;
    overflow: auto;
    position:fixed;
  }
  .cs-control button{
    border-radius: 3px;
    font-size: 14px;
  }
  .cs-control .strip{
    min-width: 99%;
    height: 20px;
    margin: 5px 0px 5px;
  }
  .cs-control .strip:hover{
    background-color: #aaffaa;
  }
  .cs-control .strip .cell{
    display: inline-block;
    margin: 0px;
    min-height: 20px;
    overflow:hidden;
  }
  .cs-control .strip .cell:hover{
    background-color: #ddffdd;
  }
`;
    //Root div of control panel.
    let root = eCreate('div');
    root.className = "cs-control";
    root.id = "cs-cp-root";
    root.appendChild(style)
    let columnNames = createStrip();
    ePush(columnNames, [
      createCell("50px", "PID"),
      createCell("150px", "Name"),
      createCell("300px", "Description"),
      createCell("200px", "Delay/interval (ms)"),
      createCell("200px", "Run at <span title = 'This is approximate time when task will be executed. For looped tasks this column shows time of first run'>(?)</span>"),
      createCell("400px", "Options")
    ]);
    root.appendChild(columnNames);
    for(name in self.tasks){
      let task = self.tasks[name],
          strip = createStrip(),
          options = eCreate('span'),
          buttonRun = eCreate('button'),
          buttonRemove = eCreate('button'),
          buttonFreeze = eCreate('button');
      buttonRun.innerHTML = "Run task";
      buttonRemove.innerHTML = "Remove task";
      buttonFreeze.innerHTML = "Freeze task";
      buttonRun.id = "run" + name;
      buttonRemove.id = "remove" + name;
      buttonFreeze.id = "freeze" + name;
      console.log(name);
      buttonRemove.addEventListener("click", function(){
        self.stop(name);
      });
      buttonRun.addEventListener("click", function(){
        self.runTask(""+name);
      });
      buttonFreeze.addEventListener("click", function(){
        self.freezeTask(name);
      });

      ePush(options,[
        buttonRun,
        buttonRemove,
        buttonFreeze
      ]);

      ePush(strip, [
        createCell("50px", task.pid),
        createCell("150px", task.name.length > 21? `<span title="${task.name}">${task.name}</span>` : task.name),
        createCell("300px", task.description.length > 42? `<span title="${task.description}">${task.description}</span>` : task.description),
        createCell("200px", task.timeout),
        createCell("200px", task.at),
        createCell("400px", options)

      ]);
      root.appendChild(strip);
    }
    document.body.appendChild(root);
    self.cpOpened = true;
    this.log("CP opened");
  };

  this.closeControlPanel = function(){
    if (!self.cpOpened)
      return;
    document.body.removeChild(document.querySelector('#cs-cp-root'));
    self.cpOpened = false;
    this.log("CP closed");
  };

  //Watch keyup and waiting for Ctr Ctrl Ctrl to open control panel
  window.addEventListener("keyup", function(e){
    if (e.key == "Control")
      self.controlCount++;
    else if (e.key == "Escape")
      self.closeControlPanel();
    if (self.controlCount>=3){
      self.controlCount = 0;
      self.openControlPanel();
    }
  });

  this.verboseLogs = verboseLogs;
  this.verboseTime = verboseTime;
  this.writeLogs = writeLogs;
  this.run(()=>{console.log("Example function executed");}, 42000000, false, "example", "This is a sample task. It will do nothing.");

}
<|endoftext|>


<commit_before>import { Meteor } from 'meteor/meteor';
import writeScript from './lib/writeScript';

Meteor.startup(() => {
    // Check if browser is IE and add the polyfill scripts
    if (navigator && /MSIE \d|Trident.*rv:/.test(navigator.userAgent)) {
        writeScript('typedarray.min.js');

        // Fix SVG+USE issues by calling the SVG polyfill
        writeScript('svg4everybody.min.js', () => window.svg4everybody());
    }
});
<commit_msg>Preventing svg polyfill from interefering on frames rendering<commit_after>import { Meteor } from 'meteor/meteor';
import { $ } from 'meteor/jquery';
import writeScript from './lib/writeScript';

// Check if browser is IE and add the polyfill scripts
if (navigator && /MSIE \d|Trident.*rv:/.test(navigator.userAgent)) {
    Meteor.startup(() => {
        // This is needed before window loading because it's used to parse DICOM images data
        writeScript('typedarray.min.js');

        $(window).on('load', () => {
            // Fix SVG+USE issues by calling the SVG polyfill
            writeScript('svg4everybody.min.js', () => window.svg4everybody());
        });
    });
}
<|endoftext|>