<commit_before>// View model for the page
function pageViewModel(gvm) {
    // Page specific i18n bindings
    gvm.app  = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("WorksheetNameRapport");}, gvm);
    gvm.title = ko.computed(function (){i18n.setLocale(gvm.lang()); return gvm.app() + ' - ' + i18n.__("HomeRapportTitle");}, gvm);
    gvm.projectname = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("ProjectRapportName");}, gvm);
    gvm.homeManual = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("WorksheetRapportManual");}, gvm);

    gvm.formequip = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("FormEquip");}, gvm);
    gvm.formmethod = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("FormMethod");}, gvm);

    gvm.userId = null;
    gvm.availableModules = ko.observableArray([]);

    gvm.updateModules = function(courseid) {
        $.getJSON('/api/coursestructure/' + courseid, function(data) {
            if (!$.isEmptyObject(data)) {
                gvm.availableModules.removeAll();

                $.each(data, function(i, item) {
                    var tblObject = {modid: item.id, modname: item.name, competences: new Array()};
                    if (item.doelstellingen.length !== 0) {
                        gvm.updateCompetences(item.doelstellingen, tblObject.competences);
                    }
                    gvm.availableModules.push(tblObject);
                });
                makeChecklist();
            }
        });
    }

    gvm.updateCompetences = function(data, competences) {
        $.each(data, function(i, item) {
            var tblObject = {comid: item.id, comname: item.name, criterias: new Array()}
            if (item.criterias.length !== 0) {
                gvm.updateCriteria(item.criterias, tblObject.criterias);
            }
            competences.push(tblObject);
        });
        makeChecklist();
    }

    gvm.updateCriteria = function(data, criteria) {
        $.each(data, function(i, item){
            var tblObject = {critid: item.id, critname: item.name};
            criteria.push(tblObject);
        });
        makeChecklist();
    }
}

function addWorksheetProperties(serialData, wid, callback) {
    var collection = getCheckedFields();
    $.ajax({
        url: "/api/worksheetproperties/" + wid,
        type: "PUT",
        data: serialData,
        success: function(data) {
            console.log(data);
            callback(false);
        },
        error: function(data) {
            callback(true);
        }
    });
    $.ajax({
        url: "/api/worksheetmodules",
        type: "POST",
        data: {id: wid, modules: collection[0], competences: collection[1], criteria: collection[2]},
        success: function(data) {
            console.log('Success');
        },
        error: function(data) {
            console.log('Failure');
        }
    });
}

function makeChecklist() {
    $('.list-group.checked-list-box .list-group-item').each(function () {

        // Settings
        var $widget = $(this),
            $checkbox = $('<input type="checkbox" class="hidden" />'),
            color = ($widget.data('color') ? $widget.data('color') : "primary"),
            style = ($widget.data('style') == "button" ? "btn-" : "list-group-item-"),
            settings = {
                on: {
                    icon: 'glyphicon glyphicon-check'
                },
                off: {
                    icon: 'glyphicon glyphicon-unchecked'
                }
            };

        $widget.css('cursor', 'pointer')
        $widget.append($checkbox);

        // Event Handlers
        $widget.on('click', function () {
            $checkbox.prop('checked', !$checkbox.is(':checked'));
            $checkbox.triggerHandler('change');
            updateDisplay();
        });
        $checkbox.on('change', function () {
            updateDisplay();
        });

        // Actions
        function updateDisplay() {
            var isChecked = $checkbox.is(':checked');

            // Set the button's state
            $widget.data('state', (isChecked) ? "on" : "off");

            // Set the button's icon
            $widget.find('.state-icon')
                .removeClass()
                .addClass('state-icon ' + settings[$widget.data('state')].icon);

            // Update the button's color
            if (isChecked) {
                $widget.addClass(style + color + ' active');
            } else {
                $widget.removeClass(style + color + ' active');
            }
        }

        // Initialization
        function init() {

            if ($widget.data('checked') == true) {
                $checkbox.prop('checked', !$checkbox.is(':checked'));
            }

            updateDisplay();

            // Inject the icon if applicable
            if ($widget.find('.state-icon').length == 0) {
                $widget.prepend('');
            }
        }
        init();
    });
}

function getCheckedFields() {
    var checkedItems = [], counter = 0;
    $("#check-list-box li.active").each(function(idx, li) {
        checkedItems[counter] = $(li).text();
        counter++;
    });
    return filterModules(checkedItems);
}

function filterModules(data) {
    var collection = [];
    var modules = [];
    var comps = [];
    var criteria = [];
    $.each(viewModel.availableModules(), function(i, item) {
        if (data.indexOf(item.modname) > -1) {
            modules.push(item.modid);
        }
        $.each(item.competences, function(i, item) {
            if (data.indexOf(item.comname) > -1) {
                comps.push(item.comid);
            }
            $.each(item.criterias, function(i, item) {
                if (data.indexOf(item.critname) > -1) {
                    criteria.push(item.critid);
                }
            });
        });
    });
    collection.push(modules);
    collection.push(comps);
    collection.push(criteria);
    return collection;
}

function initPage() {
    $.getJSON('/api/currentuser', function(data) {
        var courseid = $('#storage').attr('data-value');
        viewModel.userId = data.id;
        viewModel.updateModules(courseid);
    });

    $('#submit').click(function() {
        var wid = $('#header').attr('data-value');
        addWorksheetProperties($('#worksheetform').serialize(), wid, function() {
            $('#worksheetform').prepend("
There was a problem submitting the form
");
        });
    });
}
<commit_msg>properties van worksheet invullen via formulier<commit_after>// View model for the page
function pageViewModel(gvm) {
    // Page specific i18n bindings
    gvm.app  = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("WorksheetNameRapport");}, gvm);
    gvm.title = ko.computed(function (){i18n.setLocale(gvm.lang()); return gvm.app() + ' - ' + i18n.__("HomeRapportTitle");}, gvm);
    gvm.projectname = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("ProjectRapportName");}, gvm);
    gvm.homeManual = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("WorksheetRapportManual");}, gvm);

    gvm.formequip = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("FormEquip");}, gvm);
    gvm.formmethod = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("FormMethod");}, gvm);

    gvm.userId = null;
    gvm.availableModules = ko.observableArray([]);

    gvm.updateModules = function(courseid) {
        $.getJSON('/api/coursestructure/' + courseid, function(data) {
            if (!$.isEmptyObject(data)) {
                gvm.availableModules.removeAll();

                $.each(data, function(i, item) {
                    var tblObject = {modid: item.id, modname: item.name, competences: new Array()};
                    if (item.doelstellingen.length !== 0) {
                        console.log(item.doelstellingen.length);
                        gvm.updateCompetences(item.doelstellingen, tblObject.competences);
                    }
                    gvm.availableModules.push(tblObject);
                });
                makeChecklist();
            }
        });
    }

    gvm.updateCompetences = function(data, competences) {
        $.each(data, function(i, item) {
            var tblObject = {comid: item.id, comname: item.name, criterias: new Array()}
            if (item.criterias.length !== 0) {
                console.log(item.criterias.length);
                gvm.updateCriteria(item.criterias, tblObject.criterias);
            }
            competences.push(tblObject);
        });
        makeChecklist();
    }

    gvm.updateCriteria = function(data, criteria) {
        $.each(data, function(i, item){
            var tblObject = {critid: item.id, critname: item.name};
            criteria.push(tblObject);
        });
        makeChecklist();
    }
}

function addWorksheetProperties(serialData, wid, callback) {
    var collection = getCheckedFields();
    $.ajax({
        url: "/api/worksheetproperties/" + wid,
        type: "PUT",
        data: serialData,
        success: function(data) {
            console.log(data);
            callback(false);
        },
        error: function(data) {
            callback(true);
        }
    });
    $.ajax({
        url: "/api/worksheetmodules",
        type: "POST",
        data: {id: wid, modules: collection[0], competences: collection[1], criteria: collection[2]},
        success: function(data) {
            console.log('Success');
        },
        error: function(data) {
            console.log('Failure');
        }
    });
}

function makeChecklist() {
    $('.list-group.checked-list-box .list-group-item').each(function () {

        // Settings
        var $widget = $(this),
            $checkbox = $('<input type="checkbox" class="hidden" />'),
            color = ($widget.data('color') ? $widget.data('color') : "primary"),
            style = ($widget.data('style') == "button" ? "btn-" : "list-group-item-"),
            settings = {
                on: {
                    icon: 'glyphicon glyphicon-check'
                },
                off: {
                    icon: 'glyphicon glyphicon-unchecked'
                }
            };

        $widget.css('cursor', 'pointer')
        $widget.append($checkbox);

        // Event Handlers
        $widget.on('click', function () {
            $checkbox.prop('checked', !$checkbox.is(':checked'));
            $checkbox.triggerHandler('change');
            updateDisplay();
        });
        $checkbox.on('change', function () {
            updateDisplay();
        });

        // Actions
        function updateDisplay() {
            var isChecked = $checkbox.is(':checked');

            // Set the button's state
            $widget.data('state', (isChecked) ? "on" : "off");

            // Set the button's icon
            $widget.find('.state-icon')
                .removeClass()
                .addClass('state-icon ' + settings[$widget.data('state')].icon);

            // Update the button's color
            if (isChecked) {
                $widget.addClass(style + color + ' active');
            } else {
                $widget.removeClass(style + color + ' active');
            }
        }

        // Initialization
        function init() {

            if ($widget.data('checked') == true) {
                $checkbox.prop('checked', !$checkbox.is(':checked'));
            }

            updateDisplay();

            // Inject the icon if applicable
            if ($widget.find('.state-icon').length == 0) {
                $widget.prepend('');
            }
        }
        init();
    });
}

function getCheckedFields() {
    var checkedItems = [], counter = 0;
    $("#check-list-box li.active").each(function(idx, li) {
        checkedItems[counter] = $(li).text();
        counter++;
    });
    return filterModules(checkedItems);
}

function filterModules(data) {
    var collection = [];
    var modules = [];
    var comps = [];
    var criteria = [];
    $.each(viewModel.availableModules(), function(i, item) {
        if (data.indexOf(item.modname) > -1) {
            modules.push(item.modid);
        }
        $.each(item.competences, function(i, item) {
            if (data.indexOf(item.comname) > -1) {
                comps.push(item.comid);
            }
            $.each(item.criterias, function(i, item) {
                if (data.indexOf(item.critname) > -1) {
                    criteria.push(item.critid);
                }
            });
        });
    });
    collection.push(modules);
    collection.push(comps);
    collection.push(criteria);
    return collection;
}

function initPage() {
    $.getJSON('/api/currentuser', function(data) {
        var courseid = $('#storage').attr('data-value');
        viewModel.userId = data.id;
        viewModel.updateModules(courseid);
    });

    $('#submit').click(function() {
        var wid = $('#header').attr('data-value');
        addWorksheetProperties($('#worksheetform').serialize(), wid, function() {
            $('#worksheetform').prepend("
There was a problem submitting the form
");
        });
    });
}
<|endoftext|>


<commit_before>/* eslint-env node */

'use strict';

var Merge = require('webpack-merge');
var webpack = require('webpack');

var commonConfig = require('./webpack.common.config.js');

var optimizedConfig = Merge.smart(commonConfig, {
    output: {
        filename: '[name].[chunkhash].js'
    },
    devtool: false,
    plugins: [
        new webpack.DefinePlugin({
            'process.env.NODE_ENV': JSON.stringify('production')
        }),
        new webpack.LoaderOptionsPlugin({  // This may not be needed; legacy option for loaders written for webpack 1
            minimize: true
        }),
        new webpack.optimize.UglifyJsPlugin()
    ]
});

// requireCompatConfig only exists so that you can use RequireJS to require a
// Webpack bundle (but try not to do that if you can help it). RequireJS knows
// where to find named bundle output files, but doesn't know about
// prod-optimized bundles. So we make a redundant Webpack target that exists
// only to make a version of all the bundles without the chunkhash in the
// filename. That way, RequireJS can always find them.
//
// To be clear, this is a bad hack that exists to keep RequireJS from breaking
// for the short term. We're actively ripping RequireJS out of edx-platform
// entirely, and requireCompatConfig can completely disappear after RequireJS is
// gone.

// Step 1: Alter the bundle output names to omit the chunkhash.
var requireCompatConfig = Merge.smart(optimizedConfig, {
    output: {
        filename: '[name].js'
    }
})

// Step 2: Remove the plugin entries that generate the webpack-stats.json files
// that Django needs to look up resources. We never want to accidentally
// overwrite those because it means that we'll be serving assets with shorter
// cache times. RequireJS never looks at the webpack-stats.json file.
requireCompatConfig.plugins = requireCompatConfig.plugins.filter(
    plugin => !plugin.options || (plugin.options && plugin.options.filename != 'webpack-stats.json')
);

module.exports = [optimizedConfig, requireCompatConfig];
<commit_msg>TE-2551 Fix commons.js optimization reliability<commit_after>/* eslint-env node */

'use strict';

var Merge = require('webpack-merge');
var webpack = require('webpack');

var commonConfig = require('./webpack.common.config.js');

var optimizedConfig = Merge.smart(commonConfig, {
    output: {
        filename: '[name].[chunkhash].js'
    },
    devtool: false,
    plugins: [
        new webpack.DefinePlugin({
            'process.env.NODE_ENV': JSON.stringify('production')
        }),
        new webpack.LoaderOptionsPlugin({  // This may not be needed; legacy option for loaders written for webpack 1
            minimize: true
        }),
        new webpack.optimize.UglifyJsPlugin(),
        new webpack.optimize.CommonsChunkPlugin({
            // If the value below changes, update the render_bundle call in
            // common/djangoapps/pipeline_mako/templates/static_content.html
            name: 'commons',
            filename: 'commons.[chunkhash].js',
            minChunks: 3
        })
    ]
});

// requireCompatConfig only exists so that you can use RequireJS to require a
// Webpack bundle (but try not to do that if you can help it). RequireJS knows
// where to find named bundle output files, but doesn't know about
// prod-optimized bundles. So we make a redundant Webpack target that exists
// only to make a version of all the bundles without the chunkhash in the
// filename. That way, RequireJS can always find them.
//
// To be clear, this is a bad hack that exists to keep RequireJS from breaking
// for the short term. We're actively ripping RequireJS out of edx-platform
// entirely, and requireCompatConfig can completely disappear after RequireJS is
// gone.

// Step 1: Alter the bundle output names to omit the chunkhash.
var requireCompatConfig = Merge.smart(optimizedConfig, {
    output: {
        filename: '[name].js'
    },
    plugins: [
        new webpack.optimize.CommonsChunkPlugin({
            // If the value below changes, update the render_bundle call in
            // common/djangoapps/pipeline_mako/templates/static_content.html
            name: 'commons',
            filename: 'commons.js',
            minChunks: 3
        })
    ]
});

// Step 2: Remove the plugin entries that generate the webpack-stats.json files
// that Django needs to look up resources. We never want to accidentally
// overwrite those because it means that we'll be serving assets with shorter
// cache times. RequireJS never looks at the webpack-stats.json file.
requireCompatConfig.plugins = requireCompatConfig.plugins.filter(
    plugin => !plugin.options || (plugin.options && plugin.options.filename != 'webpack-stats.json')
);

module.exports = [optimizedConfig, requireCompatConfig];
<|endoftext|>


<commit_before>// View model for the page
function pageViewModel(gvm) {
    // Page specific i18n bindings
    gvm.app  = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("WorksheetNameRapport");}, gvm);
    gvm.title = ko.computed(function (){i18n.setLocale(gvm.lang()); return gvm.app() + ' - ' + i18n.__("HomeRapportTitle");}, gvm);
    gvm.projectname = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("ProjectRapportName");}, gvm);
    gvm.homeManual = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("WorksheetRapportManual");}, gvm);

    gvm.formequip = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("FormEquip");}, gvm);
    gvm.formmethod = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("FormMethod");}, gvm);

    gvm.userId = null;
    gvm.availableModules = ko.observableArray([]);

    gvm.updateModules = function(courseid) {
        $.getJSON('/api/coursestructure/' + courseid, function(data) {
            if (!$.isEmptyObject(data)) {
                gvm.availableModules.removeAll();

                $.each(data, function(i, item) {
                    var tblObject = {modid: item.id, modname: item.name, competences: new Array()};
                    if (item.doelstellingen.id !== 0) {
                        console.log(item.doelstellingen);
                        gvm.updateCompetences(item.doelstellingen, tblObject.competences);
                    }
                    gvm.availableModules.push(tblObject);
                });
                makeChecklist();
            }
        });
    }

    gvm.updateCompetences = function(data, competences) {
        $.each(data, function(i, item) {
            var tblObject = {comid: item.id, comname: item.name, criterias: new Array()}
            if (item.criterias.id !== 0) {
                console.log(item.criterias);
                gvm.updateCriteria(item.criterias, tblObject.criterias);
            }
            competences.push(tblObject);
        });
        makeChecklist();
    }

    gvm.updateCriteria = function(data, criteria) {
        $.each(data, function(i, item){
            var tblObject = {critid: item.id, critname: item.name};
            criteria.push(tblObject);
        });
        makeChecklist();
    }
}

function addWorksheetProperties(serialData, wid, callback) {
    var collection = getCheckedFields();
    $.ajax({
        url: "/api/worksheetproperties/" + wid,
        type: "PUT",
        data: serialData,
        success: function(data) {
            console.log(data);
            callback(false);
        },
        error: function(data) {
            callback(true);
        }
    });
    $.ajax({
        url: "/api/worksheetmodules",
        type: "POST",
        data: {id: wid, modules: collection[0], competences: collection[1], criteria: collection[2]},
        success: function(data) {
            console.log('Success');
        },
        error: function(data) {
            console.log('Failure');
        }
    });
}

function makeChecklist() {
    $('.list-group.checked-list-box .list-group-item').each(function () {

        // Settings
        var $widget = $(this),
            $checkbox = $('<input type="checkbox" class="hidden" />'),
            color = ($widget.data('color') ? $widget.data('color') : "primary"),
            style = ($widget.data('style') == "button" ? "btn-" : "list-group-item-"),
            settings = {
                on: {
                    icon: 'glyphicon glyphicon-check'
                },
                off: {
                    icon: 'glyphicon glyphicon-unchecked'
                }
            };

        $widget.css('cursor', 'pointer')
        $widget.append($checkbox);

        // Event Handlers
        $widget.on('click', function () {
            $checkbox.prop('checked', !$checkbox.is(':checked'));
            $checkbox.triggerHandler('change');
            updateDisplay();
        });
        $checkbox.on('change', function () {
            updateDisplay();
        });

        // Actions
        function updateDisplay() {
            var isChecked = $checkbox.is(':checked');

            // Set the button's state
            $widget.data('state', (isChecked) ? "on" : "off");

            // Set the button's icon
            $widget.find('.state-icon')
                .removeClass()
                .addClass('state-icon ' + settings[$widget.data('state')].icon);

            // Update the button's color
            if (isChecked) {
                $widget.addClass(style + color + ' active');
            } else {
                $widget.removeClass(style + color + ' active');
            }
        }

        // Initialization
        function init() {

            if ($widget.data('checked') == true) {
                $checkbox.prop('checked', !$checkbox.is(':checked'));
            }

            updateDisplay();

            // Inject the icon if applicable
            if ($widget.find('.state-icon').length == 0) {
                $widget.prepend('');
            }
        }
        init();
    });
}

function getCheckedFields() {
    var checkedItems = [], counter = 0;
    $("#check-list-box li.active").each(function(idx, li) {
        checkedItems[counter] = $(li).text();
        counter++;
    });
    return filterModules(checkedItems);
}

function filterModules(data) {
    var collection = [];
    var modules = [];
    var comps = [];
    var criteria = [];
    $.each(viewModel.availableModules(), function(i, item) {
        if (data.indexOf(item.modname) > -1) {
            modules.push(item.modid);
        }
        $.each(item.competences, function(i, item) {
            if (data.indexOf(item.comname) > -1) {
                comps.push(item.comid);
            }
            $.each(item.criterias, function(i, item) {
                if (data.indexOf(item.critname) > -1) {
                    criteria.push(item.critid);
                }
            });
        });
    });
    collection.push(modules);
    collection.push(comps);
    collection.push(criteria);
    return collection;
}

function initPage() {
    $.getJSON('/api/currentuser', function(data) {
        var courseid = $('#storage').attr('data-value');
        viewModel.userId = data.id;
        viewModel.updateModules(courseid);
    });

    $('#submit').click(function() {
        var wid = $('#header').attr('data-value');
        addWorksheetProperties($('#worksheetform').serialize(), wid, function() {
            $('#worksheetform').prepend("
There was a problem submitting the form
");
        });
    });
}
<commit_msg>properties van worksheet invullen via formulier<commit_after>// View model for the page
function pageViewModel(gvm) {
    // Page specific i18n bindings
    gvm.app  = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("WorksheetNameRapport");}, gvm);
    gvm.title = ko.computed(function (){i18n.setLocale(gvm.lang()); return gvm.app() + ' - ' + i18n.__("HomeRapportTitle");}, gvm);
    gvm.projectname = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("ProjectRapportName");}, gvm);
    gvm.homeManual = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("WorksheetRapportManual");}, gvm);

    gvm.formequip = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("FormEquip");}, gvm);
    gvm.formmethod = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("FormMethod");}, gvm);

    gvm.userId = null;
    gvm.availableModules = ko.observableArray([]);

    gvm.updateModules = function(courseid) {
        $.getJSON('/api/coursestructure/' + courseid, function(data) {
            if (!$.isEmptyObject(data)) {
                gvm.availableModules.removeAll();

                $.each(data, function(i, item) {
                    var tblObject = {modid: item.id, modname: item.name, competences: new Array()};
                    if (item.doelstellingen.id !== null) {
                        console.log(item.doelstellingen);
                        gvm.updateCompetences(item.doelstellingen, tblObject.competences);
                    }
                    gvm.availableModules.push(tblObject);
                });
                makeChecklist();
            }
        });
    }

    gvm.updateCompetences = function(data, competences) {
        $.each(data, function(i, item) {
            var tblObject = {comid: item.id, comname: item.name, criterias: new Array()}
            if (item.criterias.id !== null) {
                console.log(item.criterias);
                gvm.updateCriteria(item.criterias, tblObject.criterias);
            }
            competences.push(tblObject);
        });
        makeChecklist();
    }

    gvm.updateCriteria = function(data, criteria) {
        $.each(data, function(i, item){
            var tblObject = {critid: item.id, critname: item.name};
            criteria.push(tblObject);
        });
        makeChecklist();
    }
}

function addWorksheetProperties(serialData, wid, callback) {
    var collection = getCheckedFields();
    $.ajax({
        url: "/api/worksheetproperties/" + wid,
        type: "PUT",
        data: serialData,
        success: function(data) {
            console.log(data);
            callback(false);
        },
        error: function(data) {
            callback(true);
        }
    });
    $.ajax({
        url: "/api/worksheetmodules",
        type: "POST",
        data: {id: wid, modules: collection[0], competences: collection[1], criteria: collection[2]},
        success: function(data) {
            console.log('Success');
        },
        error: function(data) {
            console.log('Failure');
        }
    });
}

function makeChecklist() {
    $('.list-group.checked-list-box .list-group-item').each(function () {

        // Settings
        var $widget = $(this),
            $checkbox = $('<input type="checkbox" class="hidden" />'),
            color = ($widget.data('color') ? $widget.data('color') : "primary"),
            style = ($widget.data('style') == "button" ? "btn-" : "list-group-item-"),
            settings = {
                on: {
                    icon: 'glyphicon glyphicon-check'
                },
                off: {
                    icon: 'glyphicon glyphicon-unchecked'
                }
            };

        $widget.css('cursor', 'pointer')
        $widget.append($checkbox);

        // Event Handlers
        $widget.on('click', function () {
            $checkbox.prop('checked', !$checkbox.is(':checked'));
            $checkbox.triggerHandler('change');
            updateDisplay();
        });
        $checkbox.on('change', function () {
            updateDisplay();
        });

        // Actions
        function updateDisplay() {
            var isChecked = $checkbox.is(':checked');

            // Set the button's state
            $widget.data('state', (isChecked) ? "on" : "off");

            // Set the button's icon
            $widget.find('.state-icon')
                .removeClass()
                .addClass('state-icon ' + settings[$widget.data('state')].icon);

            // Update the button's color
            if (isChecked) {
                $widget.addClass(style + color + ' active');
            } else {
                $widget.removeClass(style + color + ' active');
            }
        }

        // Initialization
        function init() {

            if ($widget.data('checked') == true) {
                $checkbox.prop('checked', !$checkbox.is(':checked'));
            }

            updateDisplay();

            // Inject the icon if applicable
            if ($widget.find('.state-icon').length == 0) {
                $widget.prepend('');
            }
        }
        init();
    });
}

function getCheckedFields() {
    var checkedItems = [], counter = 0;
    $("#check-list-box li.active").each(function(idx, li) {
        checkedItems[counter] = $(li).text();
        counter++;
    });
    return filterModules(checkedItems);
}

function filterModules(data) {
    var collection = [];
    var modules = [];
    var comps = [];
    var criteria = [];
    $.each(viewModel.availableModules(), function(i, item) {
        if (data.indexOf(item.modname) > -1) {
            modules.push(item.modid);
        }
        $.each(item.competences, function(i, item) {
            if (data.indexOf(item.comname) > -1) {
                comps.push(item.comid);
            }
            $.each(item.criterias, function(i, item) {
                if (data.indexOf(item.critname) > -1) {
                    criteria.push(item.critid);
                }
            });
        });
    });
    collection.push(modules);
    collection.push(comps);
    collection.push(criteria);
    return collection;
}

function initPage() {
    $.getJSON('/api/currentuser', function(data) {
        var courseid = $('#storage').attr('data-value');
        viewModel.userId = data.id;
        viewModel.updateModules(courseid);
    });

    $('#submit').click(function() {
        var wid = $('#header').attr('data-value');
        addWorksheetProperties($('#worksheetform').serialize(), wid, function() {
            $('#worksheetform').prepend("
There was a problem submitting the form
");
        });
    });
}
<|endoftext|>


<commit_before>const webpack = require('webpack');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const HTMLWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');

module.exports = {
	entry: {
		main: './src/client/main.js',
		admin: './src/client/admin.js',
		vendor: [
			'@blueprintjs/core',
			'axios',
			'babel-polyfill',
			'core-js',
			'history',
			'lodash.merge',
			'localforage',
			'marked',
			'react',
			'react-animate-on-scroll',
			'react-apollo',
			'redux-devtools-extension',
			'react-dom',
			'react-redux',
			'react-responsive',
			'react-router-dom',
			'react-transition-group',
			'redux-storage',
			'redux',
			'redux-logger',
			'redux-promise-middleware',
			'redux-storage-engine-localforage',
			'redux-thunk'
		]
	},
	module: {
		rules: [
			{
				test: /\.js?$/,
				exclude: /(node_modules)/,
				use: [
					{
						loader: 'babel-loader',
						options: {
							presets: ['react', 'es2015', 'stage-0'],
							plugins: ['react-html-attrs', 'transform-class-properties', 'transform-decorators-legacy']
						}
					}
				]
			},
			{
				test: /\.scss$/,
				use: ExtractTextPlugin.extract({
					fallback: 'style-loader',
					use: [
						{ loader: 'css-loader', options: { minimize: true, sourceMap: true } },
						{ loader: 'sass-loader', options: { sourceMap: true } }
					]
				})
			},
			{
				test: /\.(ico)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
				loader: 'file-loader', options: {name: '[name].[ext]'}
			},
			{
				test: /\.(woff|woff2|eot|ttf|otf)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
				loader: 'file-loader', options: {name: 'fonts/[name].[ext]'}
			},
			{
				test: /\.(jpg|gif|png|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
				loader: 'file-loader', options: {name: 'images/[name].[ext]'}
			}
		]
	},
	output: {
		path: __dirname + '/../public',
		filename: 'js/[name]-[chunkhash].min.js',
		publicPath: '/'
	},
	plugins: [
		new CleanWebpackPlugin(
			['public'],
			{ root: __dirname + '/..' }
		),

		new webpack.optimize.OccurrenceOrderPlugin(),

		new webpack.optimize.UglifyJsPlugin({ mangle: false, sourceMap: false}),

		new webpack.DefinePlugin({
			'process.env':{
				'NODE_ENV': JSON.stringify('production')
			}
		}),

		new webpack.optimize.CommonsChunkPlugin({
			name: 'vendor',
			minChunks: Infinity
		}),

		new ExtractTextPlugin('css/[name]-[chunkhash].css'),

		new HTMLWebpackPlugin({
			filename: 'index.html',
			chunks: ['main', 'vendor'],
			template: 'src/client/assets/index.html'
		}),

		new HTMLWebpackPlugin({
			filename: 'admin.html',
			chunks: ['admin', 'vendor'],
			template: 'src/client/assets/admin.html'
		})
	],
	devtool: 'source-map'
};
<commit_msg>Revert "[ADD] Add source-map to production"<commit_after>const webpack = require('webpack');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const HTMLWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');

module.exports = {
	entry: {
		main: './src/client/main.js',
		admin: './src/client/admin.js',
		vendor: [
			'@blueprintjs/core',
			'axios',
			'babel-polyfill',
			'core-js',
			'history',
			'lodash.merge',
			'localforage',
			'marked',
			'react',
			'react-animate-on-scroll',
			'react-apollo',
			'redux-devtools-extension',
			'react-dom',
			'react-redux',
			'react-responsive',
			'react-router-dom',
			'react-transition-group',
			'redux-storage',
			'redux',
			'redux-logger',
			'redux-promise-middleware',
			'redux-storage-engine-localforage',
			'redux-thunk'
		]
	},
	module: {
		rules: [
			{
				test: /\.js?$/,
				exclude: /(node_modules)/,
				use: [
					{
						loader: 'babel-loader',
						options: {
							presets: ['react', 'es2015', 'stage-0'],
							plugins: ['react-html-attrs', 'transform-class-properties', 'transform-decorators-legacy']
						}
					}
				]
			},
			{
				test: /\.scss$/,
				use: ExtractTextPlugin.extract({
					fallback: 'style-loader',
					use: [
						{ loader: 'css-loader', options: { minimize: true, sourceMap: true } },
						{ loader: 'sass-loader', options: { sourceMap: true } }
					]
				})
			},
			{
				test: /\.(ico)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
				loader: 'file-loader', options: {name: '[name].[ext]'}
			},
			{
				test: /\.(woff|woff2|eot|ttf|otf)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
				loader: 'file-loader', options: {name: 'fonts/[name].[ext]'}
			},
			{
				test: /\.(jpg|gif|png|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
				loader: 'file-loader', options: {name: 'images/[name].[ext]'}
			}
		]
	},
	output: {
		path: __dirname + '/../public',
		filename: 'js/[name]-[chunkhash].min.js',
		publicPath: '/'
	},
	plugins: [
		new CleanWebpackPlugin(
			['public'],
			{ root: __dirname + '/..' }
		),

		new webpack.optimize.OccurrenceOrderPlugin(),

		new webpack.optimize.UglifyJsPlugin({ mangle: false, sourceMap: false}),

		new webpack.DefinePlugin({
			'process.env':{
				'NODE_ENV': JSON.stringify('production')
			}
		}),

		new webpack.optimize.CommonsChunkPlugin({
			name: 'vendor',
			minChunks: Infinity
		}),

		new ExtractTextPlugin('css/[name]-[chunkhash].css'),

		new HTMLWebpackPlugin({
			filename: 'index.html',
			chunks: ['main', 'vendor'],
			template: 'src/client/assets/index.html'
		}),

		new HTMLWebpackPlugin({
			filename: 'admin.html',
			chunks: ['admin', 'vendor'],
			template: 'src/client/assets/admin.html'
		})
	]
};
<|endoftext|>


<commit_before>import React from 'react';

export default
class Values extends React.Component {

    componentDidMount() {
        var largestHeight = null;
        for (var i = 0; i < 3; i++) {
            var height = React.findDOMNode(this.refs['col-' + i]).offsetHeight;
            if(largestHeight === null || height > largestHeight) {
                largestHeight = height;
            }
        }
        //console.log("largestHeight: " + largestHeight);
        for (i = 0; i < 3; i++) {
            React.findDOMNode(this.refs['col-' + i]).style.minHeight = largestHeight+'px';
        }
    }

    render() {
        return (

Thoughts

Other values and goals.

Real Value

                                Create software that helps people. Good developers and good software companies create products
                                that have value to real people. Software helps people, keeps them safe, or helps them more efficiently
                                create other products to help other people and I want to be a part of it.

Transparency

                                Be verbose, open, and truthful. Free speech and the world's knowledge at our fingertips
                                are things I don't take lightly living in the US. Everyone deserves transparency from their
                                government, to know full history, and have the ability to openly share thoughts with everyone
                                or only the ones the care about.

Defect

                                Innovation never comes from those that follow norms. People who go against the grain find
                                opportunities for improvement and new solutions.

        )
    }
}<commit_msg>Mom's edits, thanks mom :)<commit_after>import React from 'react';

export default
class Values extends React.Component {

    componentDidMount() {
        var largestHeight = null;
        for (var i = 0; i < 3; i++) {
            var height = React.findDOMNode(this.refs['col-' + i]).offsetHeight;
            if(largestHeight === null || height > largestHeight) {
                largestHeight = height;
            }
        }
        //console.log("largestHeight: " + largestHeight);
        for (i = 0; i < 3; i++) {
            React.findDOMNode(this.refs['col-' + i]).style.minHeight = largestHeight+'px';
        }
    }

    render() {
        return (

Thoughts

Other values and goals.

Real Value

                                Create software that is beneficial. Good developers and good software companies create products
                                that have value to real people. Software helps people, keeps them safe, or helps them more efficiently
                                create other products to help other people. I want to be a part of that.

Transparency

                                Be verbose, open, and truthful. Free speech and the world's knowledge at our fingertips
                                are things I don't take lightly living in the US. Everyone deserves transparency from their
                                government, to know full history, and have the ability to openly share thoughts with everyone
                                or only the ones they care about.

Defect

                                Innovation never comes from those that follow norms. People who go against the grain find
                                opportunities for improvement and new solutions.

        )
    }
}<|endoftext|>


<commit_before>import React, { Component, PropTypes } from 'react';
import { Route } from 'react-router';

export default class Filter extends Component {

  constructor(props, context) {
    super(props, context);
  }

  componentWillMount() {
    const { query, filter, sort, sortKeys } = this.props;
    if (query.filter) filter(query.filter);
    if (sortKeys.length) {
      if (query.sort) {
        sort(sortKeys.indexOf(query.sort));
      } else {
        sort(sortKeys.indexOf(sortKeys[0]));
      }
    }
  }

  sort(e) {
    const { directory, sort, updatePath, query } = this.props;
    const index = encodeURIComponent(e.target.id);
    const value = encodeURIComponent(e.target.value);
    updatePath(query.filter ? `${directory.options.basePath}?filter=${query.filter}&sort=${value}` : `/?sort=${value}`);
    sort(index);
  }

  filter(e) {
    const { directory, filter, updatePath, query } = this.props;
    const value = encodeURIComponent(e.target.value);
    updatePath(query.sort ? `${directory.options.basePath}?filter=${value}&sort=${query.sort}` : `/?filter=${value}`);
    filter(value);
  }

  render() {
    const { query, sortKeys } = this.props;
    const filterValue = (query.filter) ? decodeURIComponent(query.filter) : '';
    const activeSort = (query.sort) ? query.sort : sortKeys[0];

    return (

        <input onChange={this.filter.bind(this)} className='col12' placeholder='filter' type='text' value={filterValue} />
        {sortKeys.length &&

          <form onChange={this.sort.bind(this)} className='rounded-toggle'>
            {sortKeys.map((sort, i) => {
              return (

                  <input id={`${i}`} type='radio' name='sort-toggle' value={`${sort}`} defaultChecked={activeSort === sort} />
                  <label htmlFor={`${i}`} className='animate'>{`${sort}`}

              );
            })}
          </form>

}

    );
  }
}

Filter.propTypes = {
  sortKeys: PropTypes.array.isRequired,
  updatePath: PropTypes.func.isRequired,
  query: PropTypes.object.isRequired,
  directory: PropTypes.object.isRequired,
  filter: PropTypes.func.isRequired,
  sort: PropTypes.func
};
<commit_msg>Skipped basepath on conditional<commit_after>import React, { Component, PropTypes } from 'react';
import { Route } from 'react-router';

export default class Filter extends Component {

  constructor(props, context) {
    super(props, context);
  }

  componentWillMount() {
    const { query, filter, sort, sortKeys } = this.props;
    if (query.filter) filter(query.filter);
    if (sortKeys.length) {
      if (query.sort) {
        sort(sortKeys.indexOf(query.sort));
      } else {
        sort(sortKeys.indexOf(sortKeys[0]));
      }
    }
  }

  sort(e) {
    const { directory, sort, updatePath, query } = this.props;
    const index = encodeURIComponent(e.target.id);
    const value = encodeURIComponent(e.target.value);
    const bp = directory.options.basePath;
    updatePath(query.filter ? `${bp}?filter=${query.filter}&sort=${value}` : `${bp}?sort=${value}`);
    sort(index);
  }

  filter(e) {
    const { directory, filter, updatePath, query } = this.props;
    const value = encodeURIComponent(e.target.value);
    const bp = directory.options.basePath;
    updatePath(query.sort ? `${bp}?filter=${value}&sort=${query.sort}` : `${bp}?filter=${value}`);
    filter(value);
  }

  render() {
    const { query, sortKeys } = this.props;
    const filterValue = (query.filter) ? decodeURIComponent(query.filter) : '';
    const activeSort = (query.sort) ? query.sort : sortKeys[0];

    return (

        <input onChange={this.filter.bind(this)} className='col12' placeholder='filter' type='text' value={filterValue} />
        {sortKeys.length &&

          <form onChange={this.sort.bind(this)} className='rounded-toggle'>
            {sortKeys.map((sort, i) => {
              return (

                  <input id={`${i}`} type='radio' name='sort-toggle' value={`${sort}`} defaultChecked={activeSort === sort} />
                  <label htmlFor={`${i}`} className='animate'>{`${sort}`}

              );
            })}
          </form>

}

    );
  }
}

Filter.propTypes = {
  sortKeys: PropTypes.array.isRequired,
  updatePath: PropTypes.func.isRequired,
  query: PropTypes.object.isRequired,
  directory: PropTypes.object.isRequired,
  filter: PropTypes.func.isRequired,
  sort: PropTypes.func
};
<|endoftext|>


<commit_before>import React from "react"
import { Link } from "gatsby"

const ListLink = props => (

    <Link to={props.to}>{props.children}</Link>

)

const header = props => (

    <Link to="/" style={{ textShadow: "none", backgroundImage: "none" }}>

austinate.me

    </Link>

      {/* <ListLink to="/">Home</ListLink>
      <ListLink to="/contacts">Contacts</ListLink> */}
      {/* <ListLink to="/projects">Projects</ListLink> */}
      <ListLink to="/about">About</ListLink>

{props.title}

);
export default header;
<commit_msg>Fix typo in header.js<commit_after>import React from "react"
import { Link } from "gatsby"

const ListLink = props => (

    <Link to={props.to}>{props.children}</Link>

)

const header = props => (

    <Link to="/" style={{ textShadow: "none", backgroundImage: "none" }}>

austinate.me

    </Link>

      {/* <ListLink to="/">Home</ListLink>
      <ListLink to="/contacts">Contacts</ListLink> */}
      {/* <ListLink to="/projects">Projects</ListLink> */}
      <ListLink to="/about">About</ListLink>

{props.title}

);
export default header;
<|endoftext|>


<commit_before>import fs from 'fs';
import path from 'path';
import JSON5 from 'json5';
import { satisfies } from 'semver';
import { sync as resolveSync } from 'resolve';

import { logger } from '@storybook/node-logger';

function removeReactHmre(presets) {
  const index = presets.indexOf('react-hmre');
  if (index > -1) {
    presets.splice(index, 1);
  }
}

// Tries to load a .babelrc and returns the parsed object if successful
function loadFromPath(babelConfigPath) {
  let config;
  const error = {};

  if (fs.existsSync(babelConfigPath)) {
    const content = fs.readFileSync(babelConfigPath, 'utf-8');

    try {
      // eslint-disable-next-line global-require, import/no-dynamic-require
      config = require(babelConfigPath);
      logger.info('=> Loading custom babel config as JS');
    } catch (e) {
      error.js = e;
    }
    try {
      config = JSON5.parse(content);
      logger.info('=> Loading custom babel config');
    } catch (e) {
      error.json = e;
    }

    if (!config) {
      logger.error(`=> Error parsing babel config file: ${babelConfigPath}

      We tried both loading as JS & JSON, neither worked.
      Maybe there's a syntax error in the file?`);
      logger.error(`=> From JS loading we got: ${error.js.message}`);
      logger.error(`=> From JSON loading we got: ${error.js.message}`);

      throw error.js;
    }

    config.babelrc = false;
  }

  if (!config) return null;

  // Remove react-hmre preset.
  // It causes issues with react-storybook.
  // We don't really need it.
  // Earlier, we fix this by running storybook in the production mode.
  // But, that hide some useful debug messages.
  if (config.presets) {
    removeReactHmre(config.presets);
  }

  if (config.env && config.env.development && config.env.development.presets) {
    removeReactHmre(config.env.development.presets);
  }

  return config;
}

function isBabelLoader8() {
  try {
    // eslint-disable-next-line import/no-dynamic-require,global-require
    const babelLoaderPkg = require(resolveSync('babel-loader/package.json', {
      basedir: process.cwd(),
    }));
    return satisfies(babelLoaderPkg.version, '>=8.0.0-0');
  } catch (e) {
    return false;
  }
}

export default async function(configDir, getDefaultConfig) {
  const projectRoot = process.cwd();
  const babelConfig =
    loadFromPath(path.resolve(configDir, '.babelrc')) ||
    loadFromPath(path.resolve(projectRoot, 'babel.config.js'));

  if (babelConfig) {
    // If the custom config uses babel's `extends` clause, then replace it with
    // an absolute path. `extends` will not work unless we do this.
    if (babelConfig.extends) {
      babelConfig.extends = path.resolve(configDir, babelConfig.extends);
    }
    return babelConfig;
  }

  return isBabelLoader8() ? getDefaultConfig() : {};
}
<commit_msg>Don't mutate user's babel config (#6987)<commit_after>import fs from 'fs';
import path from 'path';
import JSON5 from 'json5';
import { satisfies } from 'semver';
import { sync as resolveSync } from 'resolve';

import { logger } from '@storybook/node-logger';

function removeReactHmre(presets) {
  const index = presets.indexOf('react-hmre');
  if (index > -1) {
    presets.splice(index, 1);
  }
}

// Tries to load a .babelrc and returns the parsed object if successful
function loadFromPath(babelConfigPath) {
  let config;
  const error = {};

  if (fs.existsSync(babelConfigPath)) {
    const content = fs.readFileSync(babelConfigPath, 'utf-8');

    try {
      // eslint-disable-next-line global-require, import/no-dynamic-require
      config = require(babelConfigPath);
      logger.info('=> Loading custom babel config as JS');
    } catch (e) {
      error.js = e;
    }
    try {
      config = JSON5.parse(content);
      logger.info('=> Loading custom babel config');
    } catch (e) {
      error.json = e;
    }

    if (!config) {
      logger.error(`=> Error parsing babel config file: ${babelConfigPath}

      We tried both loading as JS & JSON, neither worked.
      Maybe there's a syntax error in the file?`);
      logger.error(`=> From JS loading we got: ${error.js.message}`);
      logger.error(`=> From JSON loading we got: ${error.js.message}`);

      throw error.js;
    }

    config = { ...config, babelrc: false };
  }

  if (!config) return null;

  // Remove react-hmre preset.
  // It causes issues with react-storybook.
  // We don't really need it.
  // Earlier, we fix this by running storybook in the production mode.
  // But, that hide some useful debug messages.
  if (config.presets) {
    removeReactHmre(config.presets);
  }

  if (config.env && config.env.development && config.env.development.presets) {
    removeReactHmre(config.env.development.presets);
  }

  return config;
}

function isBabelLoader8() {
  try {
    // eslint-disable-next-line import/no-dynamic-require,global-require
    const babelLoaderPkg = require(resolveSync('babel-loader/package.json', {
      basedir: process.cwd(),
    }));
    return satisfies(babelLoaderPkg.version, '>=8.0.0-0');
  } catch (e) {
    return false;
  }
}

export default async function(configDir, getDefaultConfig) {
  const projectRoot = process.cwd();
  const babelConfig =
    loadFromPath(path.resolve(configDir, '.babelrc')) ||
    loadFromPath(path.resolve(projectRoot, 'babel.config.js'));

  if (babelConfig) {
    // If the custom config uses babel's `extends` clause, then replace it with
    // an absolute path. `extends` will not work unless we do this.
    if (babelConfig.extends) {
      babelConfig.extends = path.resolve(configDir, babelConfig.extends);
    }
    return babelConfig;
  }

  return isBabelLoader8() ? getDefaultConfig() : {};
}
<|endoftext|>


<commit_before>/**
* @license Apache-2.0
*
* Copyright (c) 2020 The Stdlib Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*    http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

'use strict';

// MODULES //

var isNonNegativeInteger = require( '@stdlib/assert/is-nonnegative-integer' ).isPrimitive;
var isPositiveInteger = require( '@stdlib/assert/is-positive-integer' );
var isInteger = require( '@stdlib/assert/is-integer' ).isPrimitive;
var isFunctionArray = require( '@stdlib/assert/is-function-array' );
var isFunction = require( '@stdlib/assert/is-function' );
var isStringArray = require( '@stdlib/assert/is-string-array' ).primitives;
var isArrayLikeObject = require( '@stdlib/assert/is-array-like-object' );
var abs = require( '@stdlib/math/base/special/abs' );
var dtype = require( '@stdlib/ndarray/base/buffer-dtype' );
var indexOfTypes = require( './index_of_types.js' );

// MAIN //

/**
* Returns a strided array function interface which performs multiple dispatch.
*
* @param {(FunctionArray|Function)} fcns - list of strided array functions
* @param {StringArray} types - one-dimensional list of strided array argument data types
* @param {(ArrayLikeObject|null)} data - strided array function data (e.g., callbacks)
* @param {PositiveInteger} nargs - total number of strided array function interface arguments (including strides and offsets)
* @param {NonNegativeInteger} nin - number of input strided arrays
* @param {NonNegativeInteger} nout - number of output strided arrays
* @throws {TypeError} first argument must be either a function or an array of functions
* @throws {TypeError} second argument must be an array of strings
* @throws {TypeError} third argument must be an array-like object or `null`
* @throws {Error} third and first arguments must have the same number of elements
* @throws {TypeError} fourth argument must be a positive integer
* @throws {TypeError} fifth argument must be a nonnegative integer
* @throws {TypeError} sixth argument must be a nonnegative integer
* @throws {Error} fourth argument must be compatible with the specified number of input and output arrays
* @throws {Error} number of types must match the number of functions times the total number of array arguments for each function
* @throws {Error} interface must accept at least one strided input and/or output array
* @returns {Function} strided array function interface
*
* @example
* var unary = require( '@stdlib/strided/base/unary' );
* var abs = require( '@stdlib/math/base/special/abs' );
* var Float64Array = require( '@stdlib/array/float64' );
*
* var types = [
*     'float64', 'float64'
* ];
*
* var data = [
*     abs
* ];
*
* var strided = dispatch( unary, types, data, 5, 1, 1 );
*
* // ...
*
* var x = new Float64Array( [ -1.0, -2.0, -3.0, -4.0, -5.0 ] );
* var y = new Float64Array( [ 0.0, 0.0, 0.0, 0.0, 0.0 ] );
*
* strided( x.length, x, 1, y, 1 );
* // y => <Float64Array>[ 1.0, 2.0, 3.0, 4.0, 5.0 ]
*/
function dispatch( fcns, types, data, nargs, nin, nout ) {
	var strideArgs;
	var hasOffsets;
	var narrays;
	var nfcns;
	var iout;
	var fcn;

	if ( isFunction( fcns ) ) {
		fcn = fcns;
	} else if ( !isFunctionArray( fcns ) ) {
		throw new TypeError( 'invalid argument. First argument must be either a function or an array of functions. Value: `' + fcns + '`.' );
	}
	if ( !isStringArray( types ) ) {
		throw new TypeError( 'invalid argument. Second argument must be an array of strings. Value: `' + types + '`.' );
	}
	if ( !isArrayLikeObject( data ) && data !== null ) {
		throw new TypeError( 'invalid argument. Third argument must be an array-like object or `null`. Value: `' + data + '`.' );
	}
	if ( !isPositiveInteger( nargs ) ) {
		throw new TypeError( 'invalid argument. Fourth argument must be a positive integer. Value: `' + nargs + '`.' );
	}
	if ( !isNonNegativeInteger( nin ) ) {
		throw new TypeError( 'invalid argument. Fifth argument must be a nonnegative integer. Value: `' + nin + '`.' );
	}
	if ( !isNonNegativeInteger( nout ) ) {
		throw new TypeError( 'invalid argument. Sixth argument must be a nonnegative integer. Value: `' + nout + '`.' );
	}
	narrays = nin + nout;
	if ( narrays === 0 ) {
		throw new Error( 'invalid arguments. Interface must accept at least one strided input and/or output array. Based on the provided arguments, `nin+nout` equals `0`.' );
	}
	if ( fcn ) {
		nfcns = types.length / narrays;
		if ( !isInteger( nfcns ) ) {
			throw new Error( 'invalid argument. Unexpected number of types. A type must be specified for each strided input and output array for each provided strided array function.' );
		}
	} else {
		nfcns = fcns.length;
		if ( types.length !== nfcns*narrays ) {
			throw new Error( 'invalid argument. Unexpected number of types. A type must be specified for each strided input and output array for each provided strided array function.' );
		}
	}
	if ( data && data.length !== nfcns ) {
		throw new Error( 'invalid argument. The third argument must have the same number of elements as the first argument.' );
	}
	// Determine whether the strided array interface includes offsets:
	if ( (narrays*2)+1 === nargs ) {
		hasOffsets = false;
	} else if ( (narrays*3)+1 === nargs ) {
		hasOffsets = true;
	} else {
		throw new Error( 'invalid argument. Fourth argument is incompatible with the number of strided input and output arrays.' );
	}
	// Determine the "stride" for accessing related arguments:
	if ( hasOffsets ) {
		strideArgs = 3;
	} else {
		strideArgs = 2;
	}
	// Compute the index of the first output strided array argument:
	iout = ( nin*strideArgs ) + 1;

	return dispatcher;

	/**
	* Strided array function interface which performs multiple dispatch.
	*
	* @private
	* @param {integer} N - number of indexed elements
	* @param {ArrayLikeObject} x - strided array
	* @param {integer} strideX - index increment for `x`
	* @param {...(ArrayLikeObject|integer|NonNegativeInteger)} args - array arguments (arrays, strides, and offsets)
	* @throws {Error} insufficient arguments
	* @throws {Error} too many arguments
	* @throws {TypeError} first argument must be an integer
	* @throws {TypeError} input array strides must be integers
	* @throws {TypeError} output array strides must be integers
	* @throws {TypeError} input array offsets must be nonnegative integers
	* @throws {TypeError} output array offsets must be nonnegative integers
	* @throws {TypeError} input array arguments must be array-like objects
	* @throws {TypeError} output array arguments must be array-like objects
	* @throws {RangeError} input array arguments must have sufficient elements based on the associated stride and the number of indexed elements
	* @throws {RangeError} output array arguments must have sufficient elements based on the associated stride and the number of indexed elements
	* @throws {TypeError} unable to resolve a strided array function supporting the provided array argument data types
	* @returns {(ArrayLikeObject|Array<ArrayLikeObject>|void)} destination array(s)
	*/
	function dispatcher() {
		var strides;
		var offsets;
		var arrays;
		var dtypes;
		var shape;
		var argc;
		var idx;
		var N;
		var v;
		var f;
		var i;
		var j;

		argc = arguments.length;
		if ( argc !== nargs ) {
			if ( argc < nargs ) {
				throw new Error( 'invalid invocation. Insufficient arguments.' );
			}
			throw new Error( 'invalid invocation. Too many arguments.' );
		}
		N = arguments[ 0 ];
		if ( !isInteger( N ) ) {
			throw new TypeError( 'invalid argument. First argument must be an integer.' );
		}
		shape = [ N ];

		// Strides for both input and output strided arrays are every `strideArgs` arguments beginning from the third argument...
		strides = [];
		for ( i = 2; i < nargs; i += strideArgs ) {
			v = arguments[ i ];
			if ( !isInteger( v ) ) {
				if ( i < iout ) {
					throw new TypeError( 'invalid argument. Input array stride argument must be an integer.' );
				} else {
					throw new TypeError( 'invalid argument. Output array stride argument must be an integer.' );
				}
			}
			strides.push( v );
		}
		if ( hasOffsets ) {
			// Offsets for both input and output strided arrays are every `strideArgs` arguments beginning from the fourth argument...
			offsets = [];
			for ( i = 3; i < nargs; i += strideArgs ) {
				v = arguments[ i ];
				if ( !isNonNegativeInteger( v ) ) {
					if ( i < iout ) {
						throw new TypeError( 'invalid argument. Input array offset argument must be a nonnegative integer.' );
					} else {
						throw new TypeError( 'invalid argument. Output array offset argument must be a nonnegative integer.' );
					}
				}
				offsets.push( v );
			}
		}
		// Input and output strided arrays are every `strideArgs` arguments beginning from the second argument...
		arrays = [];
		dtypes = [];
		for ( i = 1; i < nargs; i += strideArgs ) {
			v = arguments[ i ];
			if ( !isArrayLikeObject( v ) ) {
				if ( i < iout ) {
					throw new TypeError( 'invalid argument. Input array argument must be an array-like object.' );
				} else {
					throw new TypeError( 'invalid argument. Output array argument must be an array-like object.' );
				}
			}
			j = (i-1) / strideArgs;
			if ( hasOffsets ) {
				idx = offsets[ j ] + ( (N-1)*strides[j] );
				if ( N > 0 && (idx < 0 || idx >= v.length) ) {
					if ( i < iout ) {
						throw new RangeError( 'invalid argument. Input array argument has insufficient elements based on the associated stride and the number of indexed elements.' );
					} else {
						throw new RangeError( 'invalid argument. Output array argument has insufficient elements based on the associated stride and the number of indexed elements.' );
					}
				}
			} else if ( (N-1)*abs(strides[j]) >= v.length ) {
				if ( i < iout ) {
					throw new RangeError( 'invalid argument. Input array argument has insufficient elements based on the associated stride and the number of indexed elements.' );
				} else {
					throw new RangeError( 'invalid argument. Output array argument has insufficient elements based on the associated stride and the number of indexed elements.' );
				}
			}
			arrays.push( v );
			dtypes.push( dtype( v ) );
		}
		// Resolve the strided array function satisfying the input array types:
		idx = indexOfTypes( nfcns, narrays, types, narrays, 1, 0, dtypes, 1, 0 ); // eslint-disable-line max-len

		// Check whether we were able to successfully resolve a strided array function:
		if ( idx < 0 ) {
			throw new TypeError( 'invalid arguments. Unable to resolve a strided array function supporting the provided array argument data types.' );
		}
		// Retrieve the strided array function:
		if ( fcn ) {
			f = fcn;
		} else {
			f = fcns[ idx ];
		}
		// Evaluate the strided array function:
		if ( data ) {
			if ( hasOffsets ) {
				f( arrays, shape, strides, offsets, data[ idx ] );
			} else {
				f( arrays, shape, strides, data[ idx ] );
			}
		} else if ( hasOffsets ) {
			f( arrays, shape, strides, offsets );
		} else {
			f( arrays, shape, strides );
		}
		if ( nout === 1 ) {
			return arrays[ narrays-1 ];
		}
		if ( nout === 0 ) {
			return;
		}
		return arrays.slice( nin );
	}
}

// EXPORTS //

module.exports = dispatch;
<commit_msg>Account for array-like class objects<commit_after>/**
* @license Apache-2.0
*
* Copyright (c) 2020 The Stdlib Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*    http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

'use strict';

// MODULES //

var isNonNegativeInteger = require( '@stdlib/assert/is-nonnegative-integer' ).isPrimitive;
var isPositiveInteger = require( '@stdlib/assert/is-positive-integer' );
var isInteger = require( '@stdlib/assert/is-integer' ).isPrimitive;
var isFunctionArray = require( '@stdlib/assert/is-function-array' );
var isFunction = require( '@stdlib/assert/is-function' );
var isStringArray = require( '@stdlib/assert/is-string-array' ).primitives;
var isArrayLikeObject = require( '@stdlib/assert/is-array-like-object' );
var abs = require( '@stdlib/math/base/special/abs' );
var dtype = require( '@stdlib/ndarray/base/buffer-dtype' );
var indexOfTypes = require( './index_of_types.js' );

// MAIN //

/**
* Returns a strided array function interface which performs multiple dispatch.
*
* @param {(FunctionArray|Function)} fcns - list of strided array functions
* @param {StringArray} types - one-dimensional list of strided array argument data types
* @param {(ArrayLikeObject|null)} data - strided array function data (e.g., callbacks)
* @param {PositiveInteger} nargs - total number of strided array function interface arguments (including strides and offsets)
* @param {NonNegativeInteger} nin - number of input strided arrays
* @param {NonNegativeInteger} nout - number of output strided arrays
* @throws {TypeError} first argument must be either a function or an array of functions
* @throws {TypeError} second argument must be an array of strings
* @throws {TypeError} third argument must be an array-like object or `null`
* @throws {Error} third and first arguments must have the same number of elements
* @throws {TypeError} fourth argument must be a positive integer
* @throws {TypeError} fifth argument must be a nonnegative integer
* @throws {TypeError} sixth argument must be a nonnegative integer
* @throws {Error} fourth argument must be compatible with the specified number of input and output arrays
* @throws {Error} number of types must match the number of functions times the total number of array arguments for each function
* @throws {Error} interface must accept at least one strided input and/or output array
* @returns {Function} strided array function interface
*
* @example
* var unary = require( '@stdlib/strided/base/unary' );
* var abs = require( '@stdlib/math/base/special/abs' );
* var Float64Array = require( '@stdlib/array/float64' );
*
* var types = [
*     'float64', 'float64'
* ];
*
* var data = [
*     abs
* ];
*
* var strided = dispatch( unary, types, data, 5, 1, 1 );
*
* // ...
*
* var x = new Float64Array( [ -1.0, -2.0, -3.0, -4.0, -5.0 ] );
* var y = new Float64Array( [ 0.0, 0.0, 0.0, 0.0, 0.0 ] );
*
* strided( x.length, x, 1, y, 1 );
* // y => <Float64Array>[ 1.0, 2.0, 3.0, 4.0, 5.0 ]
*/
function dispatch( fcns, types, data, nargs, nin, nout ) {
	var strideArgs;
	var hasOffsets;
	var narrays;
	var nfcns;
	var iout;
	var fcn;

	if ( isFunction( fcns ) ) {
		fcn = fcns;
	} else if ( !isFunctionArray( fcns ) ) {
		throw new TypeError( 'invalid argument. First argument must be either a function or an array of functions. Value: `' + fcns + '`.' );
	}
	if ( !isStringArray( types ) ) {
		throw new TypeError( 'invalid argument. Second argument must be an array of strings. Value: `' + types + '`.' );
	}
	if ( !isArrayLikeObject( data ) && data !== null ) {
		throw new TypeError( 'invalid argument. Third argument must be an array-like object or `null`. Value: `' + data + '`.' );
	}
	if ( !isPositiveInteger( nargs ) ) {
		throw new TypeError( 'invalid argument. Fourth argument must be a positive integer. Value: `' + nargs + '`.' );
	}
	if ( !isNonNegativeInteger( nin ) ) {
		throw new TypeError( 'invalid argument. Fifth argument must be a nonnegative integer. Value: `' + nin + '`.' );
	}
	if ( !isNonNegativeInteger( nout ) ) {
		throw new TypeError( 'invalid argument. Sixth argument must be a nonnegative integer. Value: `' + nout + '`.' );
	}
	narrays = nin + nout;
	if ( narrays === 0 ) {
		throw new Error( 'invalid arguments. Interface must accept at least one strided input and/or output array. Based on the provided arguments, `nin+nout` equals `0`.' );
	}
	if ( fcn ) {
		nfcns = types.length / narrays;
		if ( !isInteger( nfcns ) ) {
			throw new Error( 'invalid argument. Unexpected number of types. A type must be specified for each strided input and output array for each provided strided array function.' );
		}
	} else {
		nfcns = fcns.length;
		if ( types.length !== nfcns*narrays ) {
			throw new Error( 'invalid argument. Unexpected number of types. A type must be specified for each strided input and output array for each provided strided array function.' );
		}
	}
	if ( data && data.length !== nfcns ) {
		throw new Error( 'invalid argument. The third argument must have the same number of elements as the first argument.' );
	}
	// Determine whether the strided array interface includes offsets:
	if ( (narrays*2)+1 === nargs ) {
		hasOffsets = false;
	} else if ( (narrays*3)+1 === nargs ) {
		hasOffsets = true;
	} else {
		throw new Error( 'invalid argument. Fourth argument is incompatible with the number of strided input and output arrays.' );
	}
	// Determine the "stride" for accessing related arguments:
	if ( hasOffsets ) {
		strideArgs = 3;
	} else {
		strideArgs = 2;
	}
	// Compute the index of the first output strided array argument:
	iout = ( nin*strideArgs ) + 1;

	return dispatcher;

	/**
	* Strided array function interface which performs multiple dispatch.
	*
	* @private
	* @param {integer} N - number of indexed elements
	* @param {ArrayLikeObject} x - strided array
	* @param {integer} strideX - index increment for `x`
	* @param {...(ArrayLikeObject|integer|NonNegativeInteger)} args - array arguments (arrays, strides, and offsets)
	* @throws {Error} insufficient arguments
	* @throws {Error} too many arguments
	* @throws {TypeError} first argument must be an integer
	* @throws {TypeError} input array strides must be integers
	* @throws {TypeError} output array strides must be integers
	* @throws {TypeError} input array offsets must be nonnegative integers
	* @throws {TypeError} output array offsets must be nonnegative integers
	* @throws {TypeError} input array arguments must be array-like objects
	* @throws {TypeError} output array arguments must be array-like objects
	* @throws {RangeError} input array arguments must have sufficient elements based on the associated stride and the number of indexed elements
	* @throws {RangeError} output array arguments must have sufficient elements based on the associated stride and the number of indexed elements
	* @throws {TypeError} unable to resolve a strided array function supporting the provided array argument data types
	* @returns {(ArrayLikeObject|Array<ArrayLikeObject>|void)} destination array(s)
	*/
	function dispatcher() {
		var strides;
		var offsets;
		var arrays;
		var dtypes;
		var shape;
		var argc;
		var idx;
		var N;
		var v;
		var f;
		var i;
		var j;

		argc = arguments.length;
		if ( argc !== nargs ) {
			if ( argc < nargs ) {
				throw new Error( 'invalid invocation. Insufficient arguments.' );
			}
			throw new Error( 'invalid invocation. Too many arguments.' );
		}
		N = arguments[ 0 ];
		if ( !isInteger( N ) ) {
			throw new TypeError( 'invalid argument. First argument must be an integer.' );
		}
		shape = [ N ];

		// Strides for both input and output strided arrays are every `strideArgs` arguments beginning from the third argument...
		strides = [];
		for ( i = 2; i < nargs; i += strideArgs ) {
			v = arguments[ i ];
			if ( !isInteger( v ) ) {
				if ( i < iout ) {
					throw new TypeError( 'invalid argument. Input array stride argument must be an integer.' );
				} else {
					throw new TypeError( 'invalid argument. Output array stride argument must be an integer.' );
				}
			}
			strides.push( v );
		}
		if ( hasOffsets ) {
			// Offsets for both input and output strided arrays are every `strideArgs` arguments beginning from the fourth argument...
			offsets = [];
			for ( i = 3; i < nargs; i += strideArgs ) {
				v = arguments[ i ];
				if ( !isNonNegativeInteger( v ) ) {
					if ( i < iout ) {
						throw new TypeError( 'invalid argument. Input array offset argument must be a nonnegative integer.' );
					} else {
						throw new TypeError( 'invalid argument. Output array offset argument must be a nonnegative integer.' );
					}
				}
				offsets.push( v );
			}
		}
		// Input and output strided arrays are every `strideArgs` arguments beginning from the second argument...
		arrays = [];
		dtypes = [];
		for ( i = 1; i < nargs; i += strideArgs ) {
			v = arguments[ i ];
			if ( !isArrayLikeObject( v ) ) {
				if ( i < iout ) {
					throw new TypeError( 'invalid argument. Input array argument must be an array-like object.' );
				} else {
					throw new TypeError( 'invalid argument. Output array argument must be an array-like object.' );
				}
			}
			j = (i-1) / strideArgs;
			if ( hasOffsets ) {
				idx = offsets[ j ] + ( (N-1)*strides[j] );
				if ( N > 0 && (idx < 0 || idx >= v.length) ) {
					if ( i < iout ) {
						throw new RangeError( 'invalid argument. Input array argument has insufficient elements based on the associated stride and the number of indexed elements.' );
					} else {
						throw new RangeError( 'invalid argument. Output array argument has insufficient elements based on the associated stride and the number of indexed elements.' );
					}
				}
			} else if ( (N-1)*abs(strides[j]) >= v.length ) {
				if ( i < iout ) {
					throw new RangeError( 'invalid argument. Input array argument has insufficient elements based on the associated stride and the number of indexed elements.' );
				} else {
					throw new RangeError( 'invalid argument. Output array argument has insufficient elements based on the associated stride and the number of indexed elements.' );
				}
			}
			arrays.push( v );
			dtypes.push( dtype( v ) || 'generic' );
		}
		// Resolve the strided array function satisfying the input array types:
		idx = indexOfTypes( nfcns, narrays, types, narrays, 1, 0, dtypes, 1, 0 ); // eslint-disable-line max-len

		// Check whether we were able to successfully resolve a strided array function:
		if ( idx < 0 ) {
			throw new TypeError( 'invalid arguments. Unable to resolve a strided array function supporting the provided array argument data types.' );
		}
		// Retrieve the strided array function:
		if ( fcn ) {
			f = fcn;
		} else {
			f = fcns[ idx ];
		}
		// Evaluate the strided array function:
		if ( data ) {
			if ( hasOffsets ) {
				f( arrays, shape, strides, offsets, data[ idx ] );
			} else {
				f( arrays, shape, strides, data[ idx ] );
			}
		} else if ( hasOffsets ) {
			f( arrays, shape, strides, offsets );
		} else {
			f( arrays, shape, strides );
		}
		if ( nout === 1 ) {
			return arrays[ narrays-1 ];
		}
		if ( nout === 0 ) {
			return;
		}
		return arrays.slice( nin );
	}
}

// EXPORTS //

module.exports = dispatch;
<|endoftext|>


<commit_before>// @flow
import each from 'lodash/each'
import isEmpty from 'lodash/isEmpty'

import type {Mount} from '@opentrons/components'
import {selectors as steplistSelectors, actions as steplistActions} from '../steplist'
import {reconcileFormPipette} from '../steplist/actions/handleFormChange'
import type {PipetteFields} from '../load-file'
import type {PipetteData} from '../step-generation'
import {selectors as pipetteSelectors} from '../pipettes'
import type {ThunkDispatch, GetState} from '../types'
import {updatePipettes} from './actions'
import type {EditPipettesFields, PipettesByMount} from './types'
import {createPipette} from './utils'

// TODO: BC 2018-10-24 this thunk exists because of the extra work our pipette
// reducer is doing on pipette creation. We need other reducers to receive the
// derived pipette object, so we create it here and send it out to be wholly
// swapped in by the pipette reducer, and observed by other dependent
// reducers (e.g. steplist savedForms). In the future, the createPipette logic should
// probably happen before the initial action is dispatched, in the form or mapDispatchToProps

export const editPipettes = (payload: EditPipettesFields) =>
  (dispatch: ThunkDispatch<*>, getState: GetState) => {
    const state = getState()
    const prevPipettesByMount = pipetteSelectors.getPipettesByMount(state)
    const savedForms = steplistSelectors.getSavedForms(state)

    const nextPipettesByMount: PipettesByMount = Object.keys(payload).reduce(
      (acc: PipettesByMount, mount: Mount): PipettesByMount => {
        const pipetteFields: PipetteFields = payload[mount]
        const nextPipetteModel = pipetteFields.pipetteModel
        const nextTiprackModel = isEmpty(pipetteFields.tiprackModel) ? null : pipetteFields.tiprackModel
        const nextPipette: ?PipetteData = nextPipetteModel ? createPipette(mount, nextPipetteModel, nextTiprackModel) : null
        return nextPipette ? {...acc, [mount]: nextPipette} : acc
      },
      {}
    )

    // NOTE: this clears out currently selected step form so that we're only updating savedForms
    dispatch(steplistActions.cancelStepForm())

    each(nextPipettesByMount, (nextPipette, mount) => {
      const prevPipette = prevPipettesByMount[mount]
      if ((prevPipette && prevPipette.id) !== (nextPipette && nextPipette.id)) {
        each(savedForms, (formData, stepId) => {
          if (formData.pipette === (prevPipette && prevPipette.id)) {
            dispatch(steplistActions.changeSavedStepForm({
              stepId,
              update: {
                ...reconcileFormPipette(
                  formData,
                  state,
                  (nextPipette && nextPipette.id),
                  (nextPipette && nextPipette.channels)
                ),
                pipette: nextPipette ? nextPipette.id : null,
              },
            }))
          }
        })
      }
    })

    dispatch(updatePipettes(nextPipettesByMount))
  }
<commit_msg>fix(protocol-designer): ensure pipettes are removed from step forms when nuked (#2813)<commit_after>// @flow
import each from 'lodash/each'
import isEmpty from 'lodash/isEmpty'

import type {Mount} from '@opentrons/components'
import {selectors as steplistSelectors, actions as steplistActions} from '../steplist'
import {reconcileFormPipette} from '../steplist/actions/handleFormChange'
import type {PipetteFields} from '../load-file'
import type {PipetteData} from '../step-generation'
import {selectors as pipetteSelectors} from '../pipettes'
import type {ThunkDispatch, GetState} from '../types'
import {updatePipettes} from './actions'
import type {EditPipettesFields, PipettesByMount} from './types'
import {createPipette} from './utils'

// TODO: BC 2018-10-24 this thunk exists because of the extra work our pipette
// reducer is doing on pipette creation. We need other reducers to receive the
// derived pipette object, so we create it here and send it out to be wholly
// swapped in by the pipette reducer, and observed by other dependent
// reducers (e.g. steplist savedForms). In the future, the createPipette logic should
// probably happen before the initial action is dispatched, in the form or mapDispatchToProps

export const editPipettes = (payload: EditPipettesFields) =>
  (dispatch: ThunkDispatch<*>, getState: GetState) => {
    const state = getState()
    const prevPipettesByMount = pipetteSelectors.getPipettesByMount(state)
    const savedForms = steplistSelectors.getSavedForms(state)

    const nextPipettesByMount: PipettesByMount = Object.keys(payload).reduce(
      (acc: PipettesByMount, mount: Mount): PipettesByMount => {
        const pipetteFields: PipetteFields = payload[mount]
        const nextPipetteModel = pipetteFields.pipetteModel
        const nextTiprackModel = isEmpty(pipetteFields.tiprackModel) ? null : pipetteFields.tiprackModel
        const nextPipette: ?PipetteData = nextPipetteModel ? createPipette(mount, nextPipetteModel, nextTiprackModel) : null
        return {...acc, [mount]: nextPipette}
      },
      {}
    )

    // NOTE: this clears out currently selected step form so that we're only updating savedForms
    dispatch(steplistActions.cancelStepForm())

    each(nextPipettesByMount, (nextPipette, mount) => {
      const prevPipette = prevPipettesByMount[mount]
      if ((prevPipette && prevPipette.id) !== (nextPipette && nextPipette.id)) {
        each(savedForms, (formData, stepId) => {
          if (formData.pipette === (prevPipette && prevPipette.id)) {
            dispatch(steplistActions.changeSavedStepForm({
              stepId,
              update: {
                ...reconcileFormPipette(
                  formData,
                  state,
                  (nextPipette && nextPipette.id),
                  (nextPipette && nextPipette.channels)
                ),
                pipette: nextPipette ? nextPipette.id : null,
              },
            }))
          }
        })
      }
    })

    dispatch(updatePipettes(nextPipettesByMount))
  }
<|endoftext|>


<commit_before><commit_msg>refactoring increment/decrement reducers<commit_after><|endoftext|>