<commit_before>/*jslint browser: true */
/*global ode: true, graph: true, simcontrols: true, electrophys: true,
   componentModel: true */

// wait until the document has loaded
window.addEventListener('load', function () {
    'use strict';

    var paramsRecruitmentAndSummation, paramsRecruitmentOnly,
        layout, controlsPanel, controls, dataPanel, LLDataTable,
        LCDataTable, ALDataTable, ACDataTable, inputLDataTable,
        inputCDataTable, tMax = 3000e-3, plotHandles = [];

    // set up the controls for the current clamp simulation
    paramsRecruitmentAndSummation = {
        T0L_ms: { label: 'L Base firing period', units: 'ms',
            defaultVal: 120, minVal: 0, maxVal: 500 },
        TslopeL_ms: { label: 'L Firing period slope', units: 'ms',
            defaultVal: 50, minVal: -100, maxVal: 100 },
        T0C_ms: { label: 'C Base firing period', units: 'ms',
            defaultVal: 120, minVal: 0, maxVal: 500 },
        TslopeC_ms: { label: 'C Firing period slope', units: 'ms',
            defaultVal: 50, minVal: -100, maxVal: 100 },
        pulseStart_ms: { label: 'Stimulus delay', units: 'ms',
            defaultVal: 100, minVal: 0, maxVal: tMax / 1e-3 },
        pulseHeight: { label: 'Stimulus first pulse', units: '',
            defaultVal: 0.05, minVal: -1000, maxVal: 1000 },
        pulseSubsequentHeight: { label: 'Stimulus subsequent pulses', units: '',
            defaultVal: 0.05, minVal: -1000, maxVal: 1000 },
        pulseWidth_ms: { label: 'Pulse duration', units: 'ms',
            defaultVal: 300, minVal: 0, maxVal: tMax / 1e-3 },
        isi_ms: { label: 'Inter-stimulus interval', units: 'ms',
            defaultVal: 300, minVal: 0, maxVal: tMax / 1e-3 },
        numPulses: { label: 'Number of pulses', units: '',
            defaultVal: 3, minVal: 0, maxVal: 100 },
        totalDuration_ms: { label: 'Total duration', units: 'ms',
            defaultVal: 2000, minVal: 0, maxVal: tMax / 1e-3 }
    };

    paramsRecruitmentOnly = JSON.parse(JSON.stringify(paramsRecruitmentAndSummation));
    paramsRecruitmentOnly.T0L_ms.defaultVal = 80;
    paramsRecruitmentOnly.TslopeL_ms.defaultVal = 0;
    paramsRecruitmentOnly.T0C_ms.defaultVal = 80;
    paramsRecruitmentOnly.TslopeC_ms.defaultVal = 0;

    layout = [
        ['Neural Input', ['pulseStart_ms', 'pulseHeight',
            'pulseSubsequentHeight', 'pulseWidth_ms', 'isi_ms',
            'numPulses']],
        ['Simulation Settings', ['totalDuration_ms']]
    ];

    controlsPanel = document.getElementById('TongueMuscleControls');

    // prepare tables for displaying captured data points
    dataPanel = document.getElementById('TongueMuscleData');
    dataPanel.className = 'datapanel';

    LLDataTable = document.createElement('table');
    LLDataTable.className = 'datatable';
    dataPanel.appendChild(LLDataTable);

    LCDataTable = document.createElement('table');
    LCDataTable.className = 'datatable';
    dataPanel.appendChild(LCDataTable);

    ALDataTable = document.createElement('table');
    ALDataTable.className = 'datatable';
    dataPanel.appendChild(ALDataTable);

    ACDataTable = document.createElement('table');
    ACDataTable.className = 'datatable';
    dataPanel.appendChild(ACDataTable);

    inputLDataTable = document.createElement('table');
    inputLDataTable.className = 'datatable';
    dataPanel.appendChild(inputLDataTable);

    inputCDataTable = document.createElement('table');
    inputCDataTable.className = 'datatable';
    dataPanel.appendChild(inputCDataTable);

    // simulate and plot an hh neuron with a pulse
    function runSimulation() {
        var params, model, inputL, inputC, muscle,
            prerun, result, LL, LC, AL, AC, inputLData, inputCData,
            plotPanel, plot, title;

        // create the passive membrane
        params = controls.values;
        model = componentModel.componentModel();

        inputL = electrophys.pulseTrain({
            start: params.pulseStart_ms * 1e-3,
            width: params.pulseWidth_ms * 1e-3,
            baseline: 0.001,
            height: params.pulseHeight,
            subsequentHeight: params.pulseSubsequentHeight,
            gap: params.isi_ms * 1e-3,
            num_pulses: params.numPulses
        });

        inputC = electrophys.pulseTrain({
            start: params.pulseStart_ms * 1e-3,
            width: params.pulseWidth_ms * 1e-3,
            baseline: 0.001,
            height: params.pulseHeight,
            subsequentHeight: params.pulseSubsequentHeight,
            gap: params.isi_ms * 1e-3,
            num_pulses: params.numPulses
        });

        muscle = electrophys.tongueMuscle(model, {
            inputL: inputL,
            inputC: inputC
        });

        // run it for a bit to let it reach steady state
        prerun = model.integrate({
            tMin: -60e-3,
            tMax: 0,
            tMaxStep: 1e-4,
        });

        // simulate it
        result = model.integrate({
            tMin: 0,
            tMax: params.totalDuration_ms * 1e-3,
            tMaxStep: 1e-4,
            y0: prerun.y_f
        });

        LL         = result.mapOrderedPairs(muscle.LL);
        LC         = result.mapOrderedPairs(muscle.LC);
        AL         = result.mapOrderedPairs(muscle.AL);
        AC         = result.mapOrderedPairs(muscle.AC);
        inputLData = result.mapOrderedPairs(inputL);
        inputCData = result.mapOrderedPairs(inputC);

        console.log(LL);
        console.log(LC);

        // convert to the right units
        // each ordered pair consists of a time and another variable
        LL         = LL.map         (function (l) {return [l[0] / 1e-3, l[1]];});
        LC         = LC.map         (function (l) {return [l[0] / 1e-3, l[1]];});
        AL         = AL.map         (function (a) {return [a[0] / 1e-3, a[1]];});
        AC         = AC.map         (function (a) {return [a[0] / 1e-3, a[1]];});
        inputLData = inputLData.map (function (i) {return [i[0] / 1e-3, i[1]];});
        inputCData = inputCData.map (function (i) {return [i[0] / 1e-3, i[1]];});

        // free resources from old plots
        while (plotHandles.length > 0) {
            plotHandles.pop().destroy();
        }

        // plot the results
        plotPanel = document.getElementById('TongueMusclePlots');
        plotPanel.innerHTML = '';

        // Longitudinal length
        title = document.createElement('h4');
        title.innerHTML = 'Longitudinal Length';
        title.className = 'simplotheading';
        plotPanel.appendChild(title);
        plot = document.createElement('div');
        plot.id = 'LLPlot';
        plot.style.width = '425px';
        plot.style.height = '200px';
        plotPanel.appendChild(plot);
        plotHandles.push(
            $.jqplot('LLPlot', [LL], jQuery.extend(true, {}, graphJqplot.defaultOptions(params), {
                axes: {
                    xaxis: {label:'Time (ms)'},
                    yaxis: {label:'Length (cm)'},
                },
                series: [
                    {label: 'Length', color: 'black'},
                ],
        })));
        graphJqplot.bindDataCapture('#LLPlot', LLDataTable, 'Longitudinal Length', 'Time');
        graphJqplot.bindCursorTooltip('#LLPlot', 'Time', 'ms', 'cm');

        // Circumferential length
        title = document.createElement('h4');
        title.innerHTML = 'Circumferential Length';
        title.className = 'simplotheading';
        plotPanel.appendChild(title);
        plot = document.createElement('div');
        plot.id = 'LCPlot';
        plot.style.width = '425px';
        plot.style.height = '200px';
        plotPanel.appendChild(plot);
        plotHandles.push(
            $.jqplot('LCPlot', [LC], jQuery.extend(true, {}, graphJqplot.defaultOptions(params), {
                axes: {
                    xaxis: {label:'Time (ms)'},
                    yaxis: {label:'Length (cm)'},
                },
                series: [
                    {label: 'Length', color: 'black'},
                ],
        })));
        graphJqplot.bindDataCapture('#LCPlot', LCDataTable, 'Circumferential Length', 'Time');
        graphJqplot.bindCursorTooltip('#LCPlot', 'Time', 'ms', 'cm');

        // Longitudinal activation
        title = document.createElement('h4');
        title.innerHTML = 'Longitudinal Activation';
        title.className = 'simplotheading';
        plotPanel.appendChild(title);
        plot = document.createElement('div');
        plot.id = 'ALPlot';
        plot.style.width = '425px';
        plot.style.height = '200px';
        plotPanel.appendChild(plot);
        plotHandles.push(
            $.jqplot('ALPlot', [AL], jQuery.extend(true, {}, graphJqplot.defaultOptions(params), {
                axes: {
                    xaxis: {label:'Time (ms)'},
                    yaxis: {label:'Activation'},
                },
                series: [
                    {label: 'Activation', color: 'black'},
                ],
        })));
        graphJqplot.bindDataCapture('#ALPlot', ALDataTable, 'Longitudinal Activation', 'Time');
        graphJqplot.bindCursorTooltip('#ALPlot', 'Time', 'ms', '');

        // Circumferential activation
        title = document.createElement('h4');
        title.innerHTML = 'Circumferential Activation';
        title.className = 'simplotheading';
        plotPanel.appendChild(title);
        plot = document.createElement('div');
        plot.id = 'ACPlot';
        plot.style.width = '425px';
        plot.style.height = '200px';
        plotPanel.appendChild(plot);
        plotHandles.push(
            $.jqplot('ACPlot', [AC], jQuery.extend(true, {}, graphJqplot.defaultOptions(params), {
                axes: {
                    xaxis: {label:'Time (ms)'},
                    yaxis: {label:'Activation'},
                },
                series: [
                    {label: 'Activation', color: 'black'},
                ],
        })));
        graphJqplot.bindDataCapture('#ACPlot', ACDataTable, 'Circumferential Activation', 'Time');
        graphJqplot.bindCursorTooltip('#ACPlot', 'Time', 'ms', '');

        // Longitudinal neural input
        title = document.createElement('h4');
        title.innerHTML = 'Longitudinal Neural Input';
        title.className = 'simplotheading';
        plotPanel.appendChild(title);
        plot = document.createElement('div');
        plot.id = 'inputLPlot';
        plot.style.width = '425px';
        plot.style.height = '200px';
        plotPanel.appendChild(plot);
        plotHandles.push(
            $.jqplot('inputLPlot', [inputLData], jQuery.extend(true, {}, graphJqplot.defaultOptions(params), {
                axes: {
                    xaxis: {label:'Time (ms)'},
                    yaxis: {label:'Neural Input'},
                },
                series: [
                    {label: 'Neural Input', color: 'black'},
                ],
        })));
        graphJqplot.bindDataCapture('#inputLPlot', inputLDataTable, 'Longitudinal Neural Input', 'Time');
        graphJqplot.bindCursorTooltip('#inputLPlot', 'Time', 'ms', '');

        // Circumferential neural input
        title = document.createElement('h4');
        title.innerHTML = 'Circumferential Neural Input';
        title.className = 'simplotheading';
        plotPanel.appendChild(title);
        plot = document.createElement('div');
        plot.id = 'inputCPlot';
        plot.style.width = '425px';
        plot.style.height = '200px';
        plotPanel.appendChild(plot);
        plotHandles.push(
            $.jqplot('inputCPlot', [inputCData], jQuery.extend(true, {}, graphJqplot.defaultOptions(params), {
                axes: {
                    xaxis: {label:'Time (ms)'},
                    yaxis: {label:'Neural Input'},
                },
                series: [
                    {label: 'Neural Input', color: 'black'},
                ],
        })));
        graphJqplot.bindDataCapture('#inputCPlot', inputCDataTable, 'Circumferential Neural Input', 'Time');
        graphJqplot.bindCursorTooltip('#inputCPlot', 'Time', 'ms', '');
    }

    function reset(params, layout) {
        controlsPanel.innerHTML = '';
        controls = simcontrols.controls(controlsPanel, params, layout);
        runSimulation();
    }

    function resetToRecruitmentAndSummationSim() {
        reset(paramsRecruitmentAndSummation, layout);
    }

    function resetToRecruitmentOnlySim() {
        reset(paramsRecruitmentOnly, layout);
    }

    function clearDataTables() {
        LLDataTable.innerHTML = '';
        LLDataTable.style.display = 'none';

        LCDataTable.innerHTML = '';
        LCDataTable.style.display = 'none';

        ALDataTable.innerHTML = '';
        ALDataTable.style.display = 'none';

        ACDataTable.innerHTML = '';
        ACDataTable.style.display = 'none';

        inputLDataTable.innerHTML = '';
        inputLDataTable.style.display = 'none';

        inputCDataTable.innerHTML = '';
        inputCDataTable.style.display = 'none';
    }

    (document.getElementById('TongueMuscleRunButton')
        .addEventListener('click', runSimulation, false));
    (document.getElementById('TongueMuscleRecruitmentAndSummationSimButton')
        .addEventListener('click', resetToRecruitmentAndSummationSim, false));
    (document.getElementById('TongueMuscleRecruitmentOnlySimButton')
        .addEventListener('click', resetToRecruitmentOnlySim, false));
    (document.getElementById('TongueMuscleClearDataButton')
        .addEventListener('click', clearDataTables, false));

    // make the enter key run the simulation
    controlsPanel.addEventListener('keydown',
        function (evt, element) {
            if (evt.keyCode === 13) { // enter was pressed
                controls.triggerRead();
                runSimulation();
                return false;
            }
        }, true);

    resetToRecruitmentAndSummationSim();
    clearDataTables();

}, false);

<commit_msg>Separate inputs for L and C muscles in tongue model<commit_after>/*jslint browser: true */
/*global ode: true, graph: true, simcontrols: true, electrophys: true,
   componentModel: true */

// wait until the document has loaded
window.addEventListener('load', function () {
    'use strict';

    var paramsRecruitmentAndSummation, paramsRecruitmentOnly,
        layout, controlsPanel, controls, dataPanel, LLDataTable,
        LCDataTable, ALDataTable, ACDataTable, inputLDataTable,
        inputCDataTable, tMax = 3000e-3, plotHandles = [];

    // set up the controls for the current clamp simulation
    paramsRecruitmentAndSummation = {
        T0L_ms: { label: 'L Base firing period', units: 'ms',
            defaultVal: 120, minVal: 0, maxVal: 500 },
        TslopeL_ms: { label: 'L Firing period slope', units: 'ms',
            defaultVal: 50, minVal: -100, maxVal: 100 },
        T0C_ms: { label: 'C Base firing period', units: 'ms',
            defaultVal: 120, minVal: 0, maxVal: 500 },
        TslopeC_ms: { label: 'C Firing period slope', units: 'ms',
            defaultVal: 50, minVal: -100, maxVal: 100 },
        pulseLStart_ms: { label: 'Stimulus delay', units: 'ms',
            defaultVal: 100, minVal: 0, maxVal: tMax / 1e-3 },
        pulseLHeight: { label: 'Stimulus first pulse', units: '',
            defaultVal: 0.05, minVal: -1000, maxVal: 1000 },
        pulseLSubsequentHeight: { label: 'Stimulus subsequent pulses', units: '',
            defaultVal: 0.05, minVal: -1000, maxVal: 1000 },
        pulseLWidth_ms: { label: 'Pulse duration', units: 'ms',
            defaultVal: 300, minVal: 0, maxVal: tMax / 1e-3 },
        isiL_ms: { label: 'Inter-stimulus interval', units: 'ms',
            defaultVal: 300, minVal: 0, maxVal: tMax / 1e-3 },
        numPulsesL: { label: 'Number of pulses', units: '',
            defaultVal: 3, minVal: 0, maxVal: 100 },
        pulseCStart_ms: { label: 'Stimulus delay', units: 'ms',
            defaultVal: 400, minVal: 0, maxVal: tMax / 1e-3 },
        pulseCHeight: { label: 'Stimulus first pulse', units: '',
            defaultVal: 0.05, minVal: -1000, maxVal: 1000 },
        pulseCSubsequentHeight: { label: 'Stimulus subsequent pulses', units: '',
            defaultVal: 0.05, minVal: -1000, maxVal: 1000 },
        pulseCWidth_ms: { label: 'Pulse duration', units: 'ms',
            defaultVal: 300, minVal: 0, maxVal: tMax / 1e-3 },
        isiC_ms: { label: 'Inter-stimulus interval', units: 'ms',
            defaultVal: 300, minVal: 0, maxVal: tMax / 1e-3 },
        numPulsesC: { label: 'Number of pulses', units: '',
            defaultVal: 3, minVal: 0, maxVal: 100 },
        totalDuration_ms: { label: 'Total duration', units: 'ms',
            defaultVal: 2000, minVal: 0, maxVal: tMax / 1e-3 }
    };

    paramsRecruitmentOnly = JSON.parse(JSON.stringify(paramsRecruitmentAndSummation));
    paramsRecruitmentOnly.T0L_ms.defaultVal = 80;
    paramsRecruitmentOnly.TslopeL_ms.defaultVal = 0;
    paramsRecruitmentOnly.T0C_ms.defaultVal = 80;
    paramsRecruitmentOnly.TslopeC_ms.defaultVal = 0;

    layout = [
        ['Longitudinal Neural Input', ['pulseLStart_ms', 'pulseLHeight',
            'pulseLSubsequentHeight', 'pulseLWidth_ms', 'isiL_ms',
            'numPulsesL']],
        ['Circumferential Neural Input', ['pulseCStart_ms', 'pulseCHeight',
            'pulseCSubsequentHeight', 'pulseCWidth_ms', 'isiC_ms',
            'numPulsesC']],
        ['Simulation Settings', ['totalDuration_ms']]
    ];

    controlsPanel = document.getElementById('TongueMuscleControls');

    // prepare tables for displaying captured data points
    dataPanel = document.getElementById('TongueMuscleData');
    dataPanel.className = 'datapanel';

    LLDataTable = document.createElement('table');
    LLDataTable.className = 'datatable';
    dataPanel.appendChild(LLDataTable);

    LCDataTable = document.createElement('table');
    LCDataTable.className = 'datatable';
    dataPanel.appendChild(LCDataTable);

    ALDataTable = document.createElement('table');
    ALDataTable.className = 'datatable';
    dataPanel.appendChild(ALDataTable);

    ACDataTable = document.createElement('table');
    ACDataTable.className = 'datatable';
    dataPanel.appendChild(ACDataTable);

    inputLDataTable = document.createElement('table');
    inputLDataTable.className = 'datatable';
    dataPanel.appendChild(inputLDataTable);

    inputCDataTable = document.createElement('table');
    inputCDataTable.className = 'datatable';
    dataPanel.appendChild(inputCDataTable);

    // simulate and plot an hh neuron with a pulse
    function runSimulation() {
        var params, model, inputL, inputC, muscle,
            prerun, result, LL, LC, AL, AC, inputLData, inputCData,
            plotPanel, plot, title;

        // create the passive membrane
        params = controls.values;
        model = componentModel.componentModel();

        inputL = electrophys.pulseTrain({
            start: params.pulseLStart_ms * 1e-3,
            width: params.pulseLWidth_ms * 1e-3,
            baseline: 0.001,
            height: params.pulseLHeight,
            subsequentHeight: params.pulseLSubsequentHeight,
            gap: params.isiL_ms * 1e-3,
            num_pulses: params.numPulsesL
        });

        inputC = electrophys.pulseTrain({
            start: params.pulseCStart_ms * 1e-3,
            width: params.pulseCWidth_ms * 1e-3,
            baseline: 0.001,
            height: params.pulseCHeight,
            subsequentHeight: params.pulseCSubsequentHeight,
            gap: params.isiC_ms * 1e-3,
            num_pulses: params.numPulsesC
        });

        muscle = electrophys.tongueMuscle(model, {
            LLinit: 3.08041, // cm
            ALinit: 0.00063,
            ACinit: 0.00027,
            inputL: inputL,
            inputC: inputC
        });

        // run it for a bit to let it reach steady state
        prerun = model.integrate({
            tMin: -60e-3,
            tMax: 0,
            tMaxStep: 1e-4,
        });

        // simulate it
        result = model.integrate({
            tMin: 0,
            tMax: params.totalDuration_ms * 1e-3,
            tMaxStep: 1e-4,
            y0: prerun.y_f
        });

        LL         = result.mapOrderedPairs(muscle.LL);
        LC         = result.mapOrderedPairs(muscle.LC);
        AL         = result.mapOrderedPairs(muscle.AL);
        AC         = result.mapOrderedPairs(muscle.AC);
        inputLData = result.mapOrderedPairs(inputL);
        inputCData = result.mapOrderedPairs(inputC);

        console.log(LL);
        console.log(LC);

        // convert to the right units
        // each ordered pair consists of a time and another variable
        LL         = LL.map         (function (l) {return [l[0] / 1e-3, l[1]];});
        LC         = LC.map         (function (l) {return [l[0] / 1e-3, l[1]];});
        AL         = AL.map         (function (a) {return [a[0] / 1e-3, a[1]];});
        AC         = AC.map         (function (a) {return [a[0] / 1e-3, a[1]];});
        inputLData = inputLData.map (function (i) {return [i[0] / 1e-3, i[1]];});
        inputCData = inputCData.map (function (i) {return [i[0] / 1e-3, i[1]];});

        // free resources from old plots
        while (plotHandles.length > 0) {
            plotHandles.pop().destroy();
        }

        // plot the results
        plotPanel = document.getElementById('TongueMusclePlots');
        plotPanel.innerHTML = '';

        // Longitudinal length
        title = document.createElement('h4');
        title.innerHTML = 'Longitudinal Length';
        title.className = 'simplotheading';
        plotPanel.appendChild(title);
        plot = document.createElement('div');
        plot.id = 'LLPlot';
        plot.style.width = '425px';
        plot.style.height = '200px';
        plotPanel.appendChild(plot);
        plotHandles.push(
            $.jqplot('LLPlot', [LL], jQuery.extend(true, {}, graphJqplot.defaultOptions(params), {
                axes: {
                    xaxis: {label:'Time (ms)'},
                    yaxis: {label:'Length (cm)'},
                },
                series: [
                    {label: 'Length', color: 'black'},
                ],
        })));
        graphJqplot.bindDataCapture('#LLPlot', LLDataTable, 'Longitudinal Length', 'Time');
        graphJqplot.bindCursorTooltip('#LLPlot', 'Time', 'ms', 'cm');

        // Circumferential length
        title = document.createElement('h4');
        title.innerHTML = 'Circumferential Length';
        title.className = 'simplotheading';
        plotPanel.appendChild(title);
        plot = document.createElement('div');
        plot.id = 'LCPlot';
        plot.style.width = '425px';
        plot.style.height = '200px';
        plotPanel.appendChild(plot);
        plotHandles.push(
            $.jqplot('LCPlot', [LC], jQuery.extend(true, {}, graphJqplot.defaultOptions(params), {
                axes: {
                    xaxis: {label:'Time (ms)'},
                    yaxis: {label:'Length (cm)'},
                },
                series: [
                    {label: 'Length', color: 'black'},
                ],
        })));
        graphJqplot.bindDataCapture('#LCPlot', LCDataTable, 'Circumferential Length', 'Time');
        graphJqplot.bindCursorTooltip('#LCPlot', 'Time', 'ms', 'cm');

        // Longitudinal activation
        title = document.createElement('h4');
        title.innerHTML = 'Longitudinal Activation';
        title.className = 'simplotheading';
        plotPanel.appendChild(title);
        plot = document.createElement('div');
        plot.id = 'ALPlot';
        plot.style.width = '425px';
        plot.style.height = '200px';
        plotPanel.appendChild(plot);
        plotHandles.push(
            $.jqplot('ALPlot', [AL], jQuery.extend(true, {}, graphJqplot.defaultOptions(params), {
                axes: {
                    xaxis: {label:'Time (ms)'},
                    yaxis: {label:'Activation'},
                },
                series: [
                    {label: 'Activation', color: 'black'},
                ],
        })));
        graphJqplot.bindDataCapture('#ALPlot', ALDataTable, 'Longitudinal Activation', 'Time');
        graphJqplot.bindCursorTooltip('#ALPlot', 'Time', 'ms', '');

        // Circumferential activation
        title = document.createElement('h4');
        title.innerHTML = 'Circumferential Activation';
        title.className = 'simplotheading';
        plotPanel.appendChild(title);
        plot = document.createElement('div');
        plot.id = 'ACPlot';
        plot.style.width = '425px';
        plot.style.height = '200px';
        plotPanel.appendChild(plot);
        plotHandles.push(
            $.jqplot('ACPlot', [AC], jQuery.extend(true, {}, graphJqplot.defaultOptions(params), {
                axes: {
                    xaxis: {label:'Time (ms)'},
                    yaxis: {label:'Activation'},
                },
                series: [
                    {label: 'Activation', color: 'black'},
                ],
        })));
        graphJqplot.bindDataCapture('#ACPlot', ACDataTable, 'Circumferential Activation', 'Time');
        graphJqplot.bindCursorTooltip('#ACPlot', 'Time', 'ms', '');

        // Longitudinal neural input
        title = document.createElement('h4');
        title.innerHTML = 'Longitudinal Neural Input';
        title.className = 'simplotheading';
        plotPanel.appendChild(title);
        plot = document.createElement('div');
        plot.id = 'inputLPlot';
        plot.style.width = '425px';
        plot.style.height = '200px';
        plotPanel.appendChild(plot);
        plotHandles.push(
            $.jqplot('inputLPlot', [inputLData], jQuery.extend(true, {}, graphJqplot.defaultOptions(params), {
                axes: {
                    xaxis: {label:'Time (ms)'},
                    yaxis: {label:'Neural Input'},
                },
                series: [
                    {label: 'Neural Input', color: 'black'},
                ],
        })));
        graphJqplot.bindDataCapture('#inputLPlot', inputLDataTable, 'Longitudinal Neural Input', 'Time');
        graphJqplot.bindCursorTooltip('#inputLPlot', 'Time', 'ms', '');

        // Circumferential neural input
        title = document.createElement('h4');
        title.innerHTML = 'Circumferential Neural Input';
        title.className = 'simplotheading';
        plotPanel.appendChild(title);
        plot = document.createElement('div');
        plot.id = 'inputCPlot';
        plot.style.width = '425px';
        plot.style.height = '200px';
        plotPanel.appendChild(plot);
        plotHandles.push(
            $.jqplot('inputCPlot', [inputCData], jQuery.extend(true, {}, graphJqplot.defaultOptions(params), {
                axes: {
                    xaxis: {label:'Time (ms)'},
                    yaxis: {label:'Neural Input'},
                },
                series: [
                    {label: 'Neural Input', color: 'black'},
                ],
        })));
        graphJqplot.bindDataCapture('#inputCPlot', inputCDataTable, 'Circumferential Neural Input', 'Time');
        graphJqplot.bindCursorTooltip('#inputCPlot', 'Time', 'ms', '');
    }

    function reset(params, layout) {
        controlsPanel.innerHTML = '';
        controls = simcontrols.controls(controlsPanel, params, layout);
        runSimulation();
    }

    function resetToRecruitmentAndSummationSim() {
        reset(paramsRecruitmentAndSummation, layout);
    }

    function resetToRecruitmentOnlySim() {
        reset(paramsRecruitmentOnly, layout);
    }

    function clearDataTables() {
        LLDataTable.innerHTML = '';
        LLDataTable.style.display = 'none';

        LCDataTable.innerHTML = '';
        LCDataTable.style.display = 'none';

        ALDataTable.innerHTML = '';
        ALDataTable.style.display = 'none';

        ACDataTable.innerHTML = '';
        ACDataTable.style.display = 'none';

        inputLDataTable.innerHTML = '';
        inputLDataTable.style.display = 'none';

        inputCDataTable.innerHTML = '';
        inputCDataTable.style.display = 'none';
    }

    (document.getElementById('TongueMuscleRunButton')
        .addEventListener('click', runSimulation, false));
    (document.getElementById('TongueMuscleRecruitmentAndSummationSimButton')
        .addEventListener('click', resetToRecruitmentAndSummationSim, false));
    (document.getElementById('TongueMuscleRecruitmentOnlySimButton')
        .addEventListener('click', resetToRecruitmentOnlySim, false));
    (document.getElementById('TongueMuscleClearDataButton')
        .addEventListener('click', clearDataTables, false));

    // make the enter key run the simulation
    controlsPanel.addEventListener('keydown',
        function (evt, element) {
            if (evt.keyCode === 13) { // enter was pressed
                controls.triggerRead();
                runSimulation();
                return false;
            }
        }, true);

    resetToRecruitmentAndSummationSim();
    clearDataTables();

}, false);

<|endoftext|>


<commit_before>import { PropTypes } from 'prop-types';
import { observer, inject } from 'mobx-react';

//中转作用
var __r2Locale__;

/**
 * locale翻译替换函数，根据当前str和配置的语言选项替换。
 * @param {string} str 需要被替换的文字
 */
function t(str) {
  if (!this.props.locale) {
    console.error('You must use @inject("locale") to pass this.props.locale');
    return false;
  }
  let { defaultLocale, changedLocale } = this.props.locale;
  if (!defaultLocale) {
    console.error('You must use defaultLocale of store mobx!');
    return;
  }
  if (!__r2Locale__) {
    __r2Locale__ = {};
    defaultLocale.forEach((v, k) => {
      __r2Locale__[v] = k;
    });
  }
  if (changedLocale) {
    var o = changedLocale[__r2Locale__[str]];
    if (o) {
      return o;
    }
  }
  return str;
}
/*
 * common view locale 装饰器
 */
function localeDecorator(component) {
  component.prototype.t = t;
  return component;
}
/*
 * laytou view locale 装饰器
 * @param { string } localePath 国际化文件夹路径，相对于src目录（例如locale传进去就相当于src/locale）
 *                              默认值为locale
 * @this changeLanguage layoutView提供的切换语言Event
 */
export function localeLayout(localePath = 'locale') {
  return component => {
    component.prototype.t = t;
    @inject('locale')
    @observer
    class ViewComponent extends component {
      static displayName = component.displayName || component.name;

      state = {};

      componentDidMount() {
        super.componentDidMount && super.componentDidMount();
        //使用记住的语言列表
        if (localStorage.currentLanguage) {
          this.changeLanguage(localStorage.currentLanguage)();
        }
      }
      /**
       * 语言切换，要设置好locale目录
       * @param { string } language 语言，按照文件命名来处理如zh_CN（.js）、en_US（.js）,.js可选
       * @param { function } beforCallback 语言切换前回调函数，可以用于展示加载状态
       * @param { function } afterCallback 语言切换成功回调函数，可以用于关闭加载状态
       */
      changeLanguage(language, beforCallback, afterCallback) {
        return e => {
          this.props.locale.changeLanguage(
            localePath,
            language,
            beforCallback,
            afterCallback
          );
        };
      }

      render() {
        if (!this.props.locale) {
          console.error(
            'You must use @inject("locale") to pass this.props.locale'
          );
          return false;
        }
        //等待语言列表载入后才渲染
        if (localStorage.currentLanguage && !this.props.locale.canRender) {
          return false;
        }
        return super.render();
      }
    }
    return ViewComponent;
  };
}

export default localeDecorator;
<commit_msg>rewrite locale<commit_after>import { PropTypes } from 'prop-types';
import { observer, inject } from 'mobx-react';

//中转作用
var __r2Locale__;

/**
 * locale翻译替换函数，根据当前str和配置的语言选项替换。
 * @param {string} str 需要被替换的文字
 */
function t(str) {
  if (!this.props.locale) {
    console.error('You must use @inject("locale") to pass this.props.locale');
    return false;
  }
  let { defaultLocale, changedLocale } = this.props.locale;
  if (!defaultLocale) {
    console.error('You must use defaultLocale of store mobx!');
    return;
  }
  if (!__r2Locale__) {
    __r2Locale__ = {};
    defaultLocale.forEach((v, k) => {
      __r2Locale__[v] = k;
    });
  }
  if (changedLocale) {
    var o = changedLocale[__r2Locale__[str]];
    if (o) {
      return o;
    }
  }
  return str;
}

/*
 * view locale 装饰器
 * @param { string } localePath 国际化文件夹路径，相对于src目录（例如locale传进去就相当于src/locale）
 *                              默认值为locale
 * @this changeLanguage layoutView提供的切换语言Event
 */
export function localeDecorator(localePath = 'locale') {
  return component => {
    component.prototype.t = t;
    @inject('locale')
    @observer
    class ViewComponent extends component {
      static displayName = component.displayName || component.name;

      state = {};

      componentDidMount() {
        super.componentDidMount && super.componentDidMount();
        //使用记住的语言列表
        if (localStorage.currentLanguage) {
          this.changeLanguage(localStorage.currentLanguage)();
        }
      }
      /**
       * 语言切换，要设置好locale目录
       * @param { string } language 语言，按照文件命名来处理如zh_CN（.js）、en_US（.js）,.js可选
       * @param { function } beforCallback 语言切换前回调函数，可以用于展示加载状态
       * @param { function } afterCallback 语言切换成功回调函数，可以用于关闭加载状态
       */
      changeLanguage(language, beforCallback, afterCallback) {
        return e => {
          this.props.locale.changeLanguage(
            localePath,
            language,
            beforCallback,
            afterCallback
          );
        };
      }

      render() {
        if (!this.props.locale) {
          console.error(
            'You must use @inject("locale") to pass this.props.locale'
          );
          return false;
        }
        //等待语言列表载入后才渲染
        if (localStorage.currentLanguage && !this.props.locale.canRender) {
          return false;
        }
        return super.render();
      }
    }
    return ViewComponent;
  };
}

export default localeDecorator;
<|endoftext|>


<commit_before>// Components
import VDatePickerTitle from './VDatePickerTitle'
import VDatePickerHeader from './VDatePickerHeader'
import VDatePickerDateTable from './VDatePickerDateTable'
import VDatePickerMonthTable from './VDatePickerMonthTable'
import VDatePickerYears from './VDatePickerYears'

// Mixins
import Picker from '../../mixins/picker'

// Utils
import { pad, createNativeLocaleFormatter } from './util'
import isDateAllowed from './util/isDateAllowed'
import { consoleWarn } from '../../util/console'

/* @vue/component */
export default {
  name: 'v-date-picker',

  mixins: [Picker],

  props: {
    allowedDates: Function,
    // Function formatting the day in date picker table
    dayFormat: {
      type: Function,
      default: null
    },
    disabled: Boolean,
    events: {
      type: [Array, Function, Object],
      default: () => null
    },
    eventColor: {
      type: [Array, Function, Object, String],
      default: () => 'warning'
    },
    firstDayOfWeek: {
      type: [String, Number],
      default: 0
    },
    // Function formatting the tableDate in the day/month table header
    headerDateFormat: {
      type: Function,
      default: null
    },
    locale: {
      type: String,
      default: 'en-us'
    },
    max: String,
    min: String,
    // Function formatting month in the months table
    monthFormat: {
      type: Function,
      default: null
    },
    multiple: Boolean,
    nextIcon: {
      type: String,
      default: '$vuetify.icons.next'
    },
    pickerDate: String,
    prevIcon: {
      type: String,
      default: '$vuetify.icons.prev'
    },
    reactive: Boolean,
    readonly: Boolean,
    scrollable: Boolean,
    showCurrent: {
      type: [Boolean, String],
      default: true
    },
    showWeek: Boolean,
    // Function formatting currently selected date in the picker title
    titleDateFormat: {
      type: Function,
      default: null
    },
    type: {
      type: String,
      default: 'date',
      validator: type => ['date', 'month'].includes(type) // TODO: year
    },
    value: [Array, String],
    weekdayFormat: {
      type: Function,
      default: null
    },
    // Function formatting the year in table header and pickup title
    yearFormat: {
      type: Function,
      default: null
    },
    yearIcon: String
  },

  data () {
    const now = new Date()
    return {
      activePicker: this.type.toUpperCase(),
      inputDay: null,
      inputMonth: null,
      inputYear: null,
      isReversing: false,
      now,
      // tableDate is a string in 'YYYY' / 'YYYY-M' format (leading zero for month is not required)
      tableDate: (() => {
        if (this.pickerDate) {
          return this.pickerDate
        }

        const date = (this.multiple ? this.value[this.value.length - 1] : this.value) ||
          `${now.getFullYear()}-${now.getMonth() + 1}`
        const type = this.type === 'date' ? 'month' : 'year'
        return this.sanitizeDateString(date, type)
      })()
    }
  },

  computed: {
    lastValue () {
      return this.multiple ? this.value[this.value.length - 1] : this.value
    },
    selectedMonths () {
      if (!this.value || !this.value.length || this.type === 'month') {
        return this.value
      } else if (this.multiple) {
        return this.value.map(val => val.substr(0, 7))
      } else {
        return this.value.substr(0, 7)
      }
    },
    current () {
      if (this.showCurrent === true) {
        return this.sanitizeDateString(`${this.now.getFullYear()}-${this.now.getMonth() + 1}-${this.now.getDate()}`, this.type)
      }

      return this.showCurrent || null
    },
    inputDate () {
      return this.type === 'date'
        ? `${this.inputYear}-${pad(this.inputMonth + 1)}-${pad(this.inputDay)}`
        : `${this.inputYear}-${pad(this.inputMonth + 1)}`
    },
    tableMonth () {
      return (this.pickerDate || this.tableDate).split('-')[1] - 1
    },
    tableYear () {
      return (this.pickerDate || this.tableDate).split('-')[0] * 1
    },
    minMonth () {
      return this.min ? this.sanitizeDateString(this.min, 'month') : null
    },
    maxMonth () {
      return this.max ? this.sanitizeDateString(this.max, 'month') : null
    },
    minYear () {
      return this.min ? this.sanitizeDateString(this.min, 'year') : null
    },
    maxYear () {
      return this.max ? this.sanitizeDateString(this.max, 'year') : null
    },
    formatters () {
      return {
        year: this.yearFormat || createNativeLocaleFormatter(this.locale, { year: 'numeric', timeZone: 'UTC' }, { length: 4 }),
        titleDate: this.titleDateFormat || (this.multiple ? this.defaultTitleMultipleDateFormatter : this.defaultTitleDateFormatter)
      }
    },
    defaultTitleMultipleDateFormatter () {
      if (this.value.length < 2) {
        return dates => dates.length ? this.defaultTitleDateFormatter(dates[0]) : '0 selected'
      }

      return dates => `${dates.length} selected`
    },
    defaultTitleDateFormatter () {
      const titleFormats = {
        year: { year: 'numeric', timeZone: 'UTC' },
        month: { month: 'long', timeZone: 'UTC' },
        date: { weekday: 'short', month: 'short', day: 'numeric', timeZone: 'UTC' }
      }

      const titleDateFormatter = createNativeLocaleFormatter(this.locale, titleFormats[this.type], {
        start: 0,
        length: { date: 10, month: 7, year: 4 }[this.type]
      })

      const landscapeFormatter = date => titleDateFormatter(date)
        .replace(/([^\d\s])([\d])/g, (match, nonDigit, digit) => `${nonDigit} ${digit}`)
        .replace(', ', ',<br>')

      return this.landscape ? landscapeFormatter : titleDateFormatter
    }
  },

  watch: {
    tableDate (val, prev) {
      // Make a ISO 8601 strings from val and prev for comparision, otherwise it will incorrectly
      // compare for example '2000-9' and '2000-10'
      const sanitizeType = this.type === 'month' ? 'year' : 'month'
      this.isReversing = this.sanitizeDateString(val, sanitizeType) < this.sanitizeDateString(prev, sanitizeType)
      this.$emit('update:pickerDate', val)
    },
    pickerDate (val) {
      if (val) {
        this.tableDate = val
      } else if (this.lastValue && this.type === 'date') {
        this.tableDate = this.sanitizeDateString(this.lastValue, 'month')
      } else if (this.lastValue && this.type === 'month') {
        this.tableDate = this.sanitizeDateString(this.lastValue, 'year')
      }
    },
    value (newValue, oldValue) {
      this.checkMultipleProp()
      this.setInputDate()

      if (!this.multiple && this.value && !this.pickerDate) {
        this.tableDate = this.sanitizeDateString(this.inputDate, this.type === 'month' ? 'year' : 'month')
      } else if (this.multiple && this.value.length && !oldValue.length && !this.pickerDate) {
        this.tableDate = this.sanitizeDateString(this.inputDate, this.type === 'month' ? 'year' : 'month')
      }
    },
    type (type) {
      this.activePicker = type.toUpperCase()

      if (this.value && this.value.length) {
        const output = (this.multiple ? this.value : [this.value])
          .map(val => this.sanitizeDateString(val, type))
          .filter(this.isDateAllowed)
        this.$emit('input', this.multiple ? output : output[0])
      }
    }
  },

  created () {
    this.checkMultipleProp()

    if (this.pickerDate !== this.tableDate) {
      this.$emit('update:pickerDate', this.tableDate)
    }
    this.setInputDate()
  },

  methods: {
    emitInput (newInput) {
      const output = this.multiple
        ? (
          this.value.indexOf(newInput) === -1
            ? this.value.concat([newInput])
            : this.value.filter(x => x !== newInput)
        )
        : newInput

      this.$emit('input', output)
      this.multiple || this.$emit('change', newInput)
    },
    checkMultipleProp () {
      if (this.value == null) return
      const valueType = this.value.constructor.name
      const expected = this.multiple ? 'Array' : 'String'
      if (valueType !== expected) {
        consoleWarn(`Value must be ${this.multiple ? 'an' : 'a'} ${expected}, got ${valueType}`, this)
      }
    },
    isDateAllowed (value) {
      return isDateAllowed(value, this.min, this.max, this.allowedDates)
    },
    yearClick (value) {
      this.inputYear = value
      if (this.type === 'month') {
        this.tableDate = `${value}`
      } else {
        this.tableDate = `${value}-${pad(this.tableMonth + 1)}`
      }
      this.activePicker = 'MONTH'
      if (this.reactive && !this.readonly && !this.multiple && this.isDateAllowed(this.inputDate)) {
        this.$emit('input', this.inputDate)
      }
    },
    monthClick (value) {
      this.inputYear = parseInt(value.split('-')[0], 10)
      this.inputMonth = parseInt(value.split('-')[1], 10) - 1
      if (this.type === 'date') {
        this.tableDate = value
        this.activePicker = 'DATE'
        if (this.reactive && !this.readonly && !this.multiple && this.isDateAllowed(this.inputDate)) {
          this.$emit('input', this.inputDate)
        }
      } else {
        this.emitInput(this.inputDate)
      }
    },
    dateClick (value) {
      this.inputYear = parseInt(value.split('-')[0], 10)
      this.inputMonth = parseInt(value.split('-')[1], 10) - 1
      this.inputDay = parseInt(value.split('-')[2], 10)
      this.emitInput(this.inputDate)
    },
    genPickerTitle () {
      return this.$createElement(VDatePickerTitle, {
        props: {
          date: this.value ? this.formatters.titleDate(this.value) : '',
          disabled: this.disabled,
          readonly: this.readonly,
          selectingYear: this.activePicker === 'YEAR',
          value: this.multiple ? this.value[0] : this.value,
          year: this.formatters.year(`${this.inputYear}`),
          yearIcon: this.yearIcon
        },
        slot: 'title',
        on: {
          'update:selectingYear': value => this.activePicker = value ? 'YEAR' : this.type.toUpperCase()
        }
      })
    },
    genTableHeader () {
      return this.$createElement(VDatePickerHeader, {
        props: {
          nextIcon: this.nextIcon,
          color: this.color,
          dark: this.dark,
          disabled: this.disabled,
          format: this.headerDateFormat,
          light: this.light,
          locale: this.locale,
          min: this.activePicker === 'DATE' ? this.minMonth : this.minYear,
          max: this.activePicker === 'DATE' ? this.maxMonth : this.maxYear,
          prevIcon: this.prevIcon,
          readonly: this.readonly,
          value: this.activePicker === 'DATE' ? `${this.tableYear}-${pad(this.tableMonth + 1)}` : `${this.tableYear}`
        },
        on: {
          toggle: () => this.activePicker = (this.activePicker === 'DATE' ? 'MONTH' : 'YEAR'),
          input: value => this.tableDate = value
        }
      })
    },
    genDateTable () {
      return this.$createElement(VDatePickerDateTable, {
        props: {
          allowedDates: this.allowedDates,
          color: this.color,
          current: this.current,
          dark: this.dark,
          disabled: this.disabled,
          events: this.events,
          eventColor: this.eventColor,
          firstDayOfWeek: this.firstDayOfWeek,
          format: this.dayFormat,
          light: this.light,
          locale: this.locale,
          min: this.min,
          max: this.max,
          readonly: this.readonly,
          scrollable: this.scrollable,
          showWeek: this.showWeek,
          tableDate: `${this.tableYear}-${pad(this.tableMonth + 1)}`,
          value: this.value,
          weekdayFormat: this.weekdayFormat
        },
        ref: 'table',
        on: {
          input: this.dateClick,
          tableDate: value => this.tableDate = value
        }
      })
    },
    genMonthTable () {
      return this.$createElement(VDatePickerMonthTable, {
        props: {
          allowedDates: this.type === 'month' ? this.allowedDates : null,
          color: this.color,
          current: this.current ? this.sanitizeDateString(this.current, 'month') : null,
          dark: this.dark,
          disabled: this.disabled,
          events: this.type === 'month' ? this.events : null,
          eventColor: this.type === 'month' ? this.eventColor : null,
          format: this.monthFormat,
          light: this.light,
          locale: this.locale,
          min: this.minMonth,
          max: this.maxMonth,
          readonly: this.readonly && this.type === 'month',
          scrollable: this.scrollable,
          value: this.selectedMonths,
          tableDate: `${this.tableYear}`
        },
        ref: 'table',
        on: {
          input: this.monthClick,
          tableDate: value => this.tableDate = value
        }
      })
    },
    genYears () {
      return this.$createElement(VDatePickerYears, {
        props: {
          color: this.color,
          format: this.yearFormat,
          locale: this.locale,
          min: this.minYear,
          max: this.maxYear,
          value: `${this.tableYear}`
        },
        on: {
          input: this.yearClick
        }
      })
    },
    genPickerBody () {
      const children = this.activePicker === 'YEAR' ? [
        this.genYears()
      ] : [
        this.genTableHeader(),
        this.activePicker === 'DATE' ? this.genDateTable() : this.genMonthTable()
      ]

      return this.$createElement('div', {
        key: this.activePicker
      }, children)
    },
    // Adds leading zero to month/day if necessary, returns 'YYYY' if type = 'year',
    // 'YYYY-MM' if 'month' and 'YYYY-MM-DD' if 'date'
    sanitizeDateString (dateString, type) {
      const [year, month = 1, date = 1] = dateString.split('-')
      return `${year}-${pad(month)}-${pad(date)}`.substr(0, { date: 10, month: 7, year: 4 }[type])
    },
    setInputDate () {
      if (this.lastValue) {
        const array = this.lastValue.split('-')
        this.inputYear = parseInt(array[0], 10)
        this.inputMonth = parseInt(array[1], 10) - 1
        if (this.type === 'date') {
          this.inputDay = parseInt(array[2], 10)
        }
      } else {
        this.inputYear = this.inputYear || this.now.getFullYear()
        this.inputMonth = this.inputMonth == null ? this.inputMonth : this.now.getMonth()
        this.inputDay = this.inputDay || this.now.getDate()
      }
    }
  },

  render () {
    return this.genPicker('v-picker--date')
  }
}
<commit_msg>refactor(VDatePicker): sort props<commit_after>// Components
import VDatePickerTitle from './VDatePickerTitle'
import VDatePickerHeader from './VDatePickerHeader'
import VDatePickerDateTable from './VDatePickerDateTable'
import VDatePickerMonthTable from './VDatePickerMonthTable'
import VDatePickerYears from './VDatePickerYears'

// Mixins
import Picker from '../../mixins/picker'

// Utils
import { pad, createNativeLocaleFormatter } from './util'
import isDateAllowed from './util/isDateAllowed'
import { consoleWarn } from '../../util/console'

/* @vue/component */
export default {
  name: 'v-date-picker',

  mixins: [Picker],

  props: {
    allowedDates: Function,
    // Function formatting the day in date picker table
    dayFormat: {
      type: Function,
      default: null
    },
    disabled: Boolean,
    events: {
      type: [Array, Function, Object],
      default: () => null
    },
    eventColor: {
      type: [Array, Function, Object, String],
      default: () => 'warning'
    },
    firstDayOfWeek: {
      type: [String, Number],
      default: 0
    },
    // Function formatting the tableDate in the day/month table header
    headerDateFormat: {
      type: Function,
      default: null
    },
    locale: {
      type: String,
      default: 'en-us'
    },
    max: String,
    min: String,
    // Function formatting month in the months table
    monthFormat: {
      type: Function,
      default: null
    },
    multiple: Boolean,
    nextIcon: {
      type: String,
      default: '$vuetify.icons.next'
    },
    pickerDate: String,
    prevIcon: {
      type: String,
      default: '$vuetify.icons.prev'
    },
    reactive: Boolean,
    readonly: Boolean,
    scrollable: Boolean,
    showCurrent: {
      type: [Boolean, String],
      default: true
    },
    showWeek: Boolean,
    // Function formatting currently selected date in the picker title
    titleDateFormat: {
      type: Function,
      default: null
    },
    type: {
      type: String,
      default: 'date',
      validator: type => ['date', 'month'].includes(type) // TODO: year
    },
    value: [Array, String],
    weekdayFormat: {
      type: Function,
      default: null
    },
    // Function formatting the year in table header and pickup title
    yearFormat: {
      type: Function,
      default: null
    },
    yearIcon: String
  },

  data () {
    const now = new Date()
    return {
      activePicker: this.type.toUpperCase(),
      inputDay: null,
      inputMonth: null,
      inputYear: null,
      isReversing: false,
      now,
      // tableDate is a string in 'YYYY' / 'YYYY-M' format (leading zero for month is not required)
      tableDate: (() => {
        if (this.pickerDate) {
          return this.pickerDate
        }

        const date = (this.multiple ? this.value[this.value.length - 1] : this.value) ||
          `${now.getFullYear()}-${now.getMonth() + 1}`
        const type = this.type === 'date' ? 'month' : 'year'
        return this.sanitizeDateString(date, type)
      })()
    }
  },

  computed: {
    lastValue () {
      return this.multiple ? this.value[this.value.length - 1] : this.value
    },
    selectedMonths () {
      if (!this.value || !this.value.length || this.type === 'month') {
        return this.value
      } else if (this.multiple) {
        return this.value.map(val => val.substr(0, 7))
      } else {
        return this.value.substr(0, 7)
      }
    },
    current () {
      if (this.showCurrent === true) {
        return this.sanitizeDateString(`${this.now.getFullYear()}-${this.now.getMonth() + 1}-${this.now.getDate()}`, this.type)
      }

      return this.showCurrent || null
    },
    inputDate () {
      return this.type === 'date'
        ? `${this.inputYear}-${pad(this.inputMonth + 1)}-${pad(this.inputDay)}`
        : `${this.inputYear}-${pad(this.inputMonth + 1)}`
    },
    tableMonth () {
      return (this.pickerDate || this.tableDate).split('-')[1] - 1
    },
    tableYear () {
      return (this.pickerDate || this.tableDate).split('-')[0] * 1
    },
    minMonth () {
      return this.min ? this.sanitizeDateString(this.min, 'month') : null
    },
    maxMonth () {
      return this.max ? this.sanitizeDateString(this.max, 'month') : null
    },
    minYear () {
      return this.min ? this.sanitizeDateString(this.min, 'year') : null
    },
    maxYear () {
      return this.max ? this.sanitizeDateString(this.max, 'year') : null
    },
    formatters () {
      return {
        year: this.yearFormat || createNativeLocaleFormatter(this.locale, { year: 'numeric', timeZone: 'UTC' }, { length: 4 }),
        titleDate: this.titleDateFormat || (this.multiple ? this.defaultTitleMultipleDateFormatter : this.defaultTitleDateFormatter)
      }
    },
    defaultTitleMultipleDateFormatter () {
      if (this.value.length < 2) {
        return dates => dates.length ? this.defaultTitleDateFormatter(dates[0]) : '0 selected'
      }

      return dates => `${dates.length} selected`
    },
    defaultTitleDateFormatter () {
      const titleFormats = {
        year: { year: 'numeric', timeZone: 'UTC' },
        month: { month: 'long', timeZone: 'UTC' },
        date: { weekday: 'short', month: 'short', day: 'numeric', timeZone: 'UTC' }
      }

      const titleDateFormatter = createNativeLocaleFormatter(this.locale, titleFormats[this.type], {
        start: 0,
        length: { date: 10, month: 7, year: 4 }[this.type]
      })

      const landscapeFormatter = date => titleDateFormatter(date)
        .replace(/([^\d\s])([\d])/g, (match, nonDigit, digit) => `${nonDigit} ${digit}`)
        .replace(', ', ',<br>')

      return this.landscape ? landscapeFormatter : titleDateFormatter
    }
  },

  watch: {
    tableDate (val, prev) {
      // Make a ISO 8601 strings from val and prev for comparision, otherwise it will incorrectly
      // compare for example '2000-9' and '2000-10'
      const sanitizeType = this.type === 'month' ? 'year' : 'month'
      this.isReversing = this.sanitizeDateString(val, sanitizeType) < this.sanitizeDateString(prev, sanitizeType)
      this.$emit('update:pickerDate', val)
    },
    pickerDate (val) {
      if (val) {
        this.tableDate = val
      } else if (this.lastValue && this.type === 'date') {
        this.tableDate = this.sanitizeDateString(this.lastValue, 'month')
      } else if (this.lastValue && this.type === 'month') {
        this.tableDate = this.sanitizeDateString(this.lastValue, 'year')
      }
    },
    value (newValue, oldValue) {
      this.checkMultipleProp()
      this.setInputDate()

      if (!this.multiple && this.value && !this.pickerDate) {
        this.tableDate = this.sanitizeDateString(this.inputDate, this.type === 'month' ? 'year' : 'month')
      } else if (this.multiple && this.value.length && !oldValue.length && !this.pickerDate) {
        this.tableDate = this.sanitizeDateString(this.inputDate, this.type === 'month' ? 'year' : 'month')
      }
    },
    type (type) {
      this.activePicker = type.toUpperCase()

      if (this.value && this.value.length) {
        const output = (this.multiple ? this.value : [this.value])
          .map(val => this.sanitizeDateString(val, type))
          .filter(this.isDateAllowed)
        this.$emit('input', this.multiple ? output : output[0])
      }
    }
  },

  created () {
    this.checkMultipleProp()

    if (this.pickerDate !== this.tableDate) {
      this.$emit('update:pickerDate', this.tableDate)
    }
    this.setInputDate()
  },

  methods: {
    emitInput (newInput) {
      const output = this.multiple
        ? (
          this.value.indexOf(newInput) === -1
            ? this.value.concat([newInput])
            : this.value.filter(x => x !== newInput)
        )
        : newInput

      this.$emit('input', output)
      this.multiple || this.$emit('change', newInput)
    },
    checkMultipleProp () {
      if (this.value == null) return
      const valueType = this.value.constructor.name
      const expected = this.multiple ? 'Array' : 'String'
      if (valueType !== expected) {
        consoleWarn(`Value must be ${this.multiple ? 'an' : 'a'} ${expected}, got ${valueType}`, this)
      }
    },
    isDateAllowed (value) {
      return isDateAllowed(value, this.min, this.max, this.allowedDates)
    },
    yearClick (value) {
      this.inputYear = value
      if (this.type === 'month') {
        this.tableDate = `${value}`
      } else {
        this.tableDate = `${value}-${pad(this.tableMonth + 1)}`
      }
      this.activePicker = 'MONTH'
      if (this.reactive && !this.readonly && !this.multiple && this.isDateAllowed(this.inputDate)) {
        this.$emit('input', this.inputDate)
      }
    },
    monthClick (value) {
      this.inputYear = parseInt(value.split('-')[0], 10)
      this.inputMonth = parseInt(value.split('-')[1], 10) - 1
      if (this.type === 'date') {
        this.tableDate = value
        this.activePicker = 'DATE'
        if (this.reactive && !this.readonly && !this.multiple && this.isDateAllowed(this.inputDate)) {
          this.$emit('input', this.inputDate)
        }
      } else {
        this.emitInput(this.inputDate)
      }
    },
    dateClick (value) {
      this.inputYear = parseInt(value.split('-')[0], 10)
      this.inputMonth = parseInt(value.split('-')[1], 10) - 1
      this.inputDay = parseInt(value.split('-')[2], 10)
      this.emitInput(this.inputDate)
    },
    genPickerTitle () {
      return this.$createElement(VDatePickerTitle, {
        props: {
          date: this.value ? this.formatters.titleDate(this.value) : '',
          disabled: this.disabled,
          readonly: this.readonly,
          selectingYear: this.activePicker === 'YEAR',
          year: this.formatters.year(`${this.inputYear}`),
          yearIcon: this.yearIcon,
          value: this.multiple ? this.value[0] : this.value
        },
        slot: 'title',
        on: {
          'update:selectingYear': value => this.activePicker = value ? 'YEAR' : this.type.toUpperCase()
        }
      })
    },
    genTableHeader () {
      return this.$createElement(VDatePickerHeader, {
        props: {
          nextIcon: this.nextIcon,
          color: this.color,
          dark: this.dark,
          disabled: this.disabled,
          format: this.headerDateFormat,
          light: this.light,
          locale: this.locale,
          min: this.activePicker === 'DATE' ? this.minMonth : this.minYear,
          max: this.activePicker === 'DATE' ? this.maxMonth : this.maxYear,
          prevIcon: this.prevIcon,
          readonly: this.readonly,
          value: this.activePicker === 'DATE' ? `${this.tableYear}-${pad(this.tableMonth + 1)}` : `${this.tableYear}`
        },
        on: {
          toggle: () => this.activePicker = (this.activePicker === 'DATE' ? 'MONTH' : 'YEAR'),
          input: value => this.tableDate = value
        }
      })
    },
    genDateTable () {
      return this.$createElement(VDatePickerDateTable, {
        props: {
          allowedDates: this.allowedDates,
          color: this.color,
          current: this.current,
          dark: this.dark,
          disabled: this.disabled,
          events: this.events,
          eventColor: this.eventColor,
          firstDayOfWeek: this.firstDayOfWeek,
          format: this.dayFormat,
          light: this.light,
          locale: this.locale,
          min: this.min,
          max: this.max,
          readonly: this.readonly,
          scrollable: this.scrollable,
          showWeek: this.showWeek,
          tableDate: `${this.tableYear}-${pad(this.tableMonth + 1)}`,
          value: this.value,
          weekdayFormat: this.weekdayFormat
        },
        ref: 'table',
        on: {
          input: this.dateClick,
          tableDate: value => this.tableDate = value
        }
      })
    },
    genMonthTable () {
      return this.$createElement(VDatePickerMonthTable, {
        props: {
          allowedDates: this.type === 'month' ? this.allowedDates : null,
          color: this.color,
          current: this.current ? this.sanitizeDateString(this.current, 'month') : null,
          dark: this.dark,
          disabled: this.disabled,
          events: this.type === 'month' ? this.events : null,
          eventColor: this.type === 'month' ? this.eventColor : null,
          format: this.monthFormat,
          light: this.light,
          locale: this.locale,
          min: this.minMonth,
          max: this.maxMonth,
          readonly: this.readonly && this.type === 'month',
          scrollable: this.scrollable,
          value: this.selectedMonths,
          tableDate: `${this.tableYear}`
        },
        ref: 'table',
        on: {
          input: this.monthClick,
          tableDate: value => this.tableDate = value
        }
      })
    },
    genYears () {
      return this.$createElement(VDatePickerYears, {
        props: {
          color: this.color,
          format: this.yearFormat,
          locale: this.locale,
          min: this.minYear,
          max: this.maxYear,
          value: `${this.tableYear}`
        },
        on: {
          input: this.yearClick
        }
      })
    },
    genPickerBody () {
      const children = this.activePicker === 'YEAR' ? [
        this.genYears()
      ] : [
        this.genTableHeader(),
        this.activePicker === 'DATE' ? this.genDateTable() : this.genMonthTable()
      ]

      return this.$createElement('div', {
        key: this.activePicker
      }, children)
    },
    // Adds leading zero to month/day if necessary, returns 'YYYY' if type = 'year',
    // 'YYYY-MM' if 'month' and 'YYYY-MM-DD' if 'date'
    sanitizeDateString (dateString, type) {
      const [year, month = 1, date = 1] = dateString.split('-')
      return `${year}-${pad(month)}-${pad(date)}`.substr(0, { date: 10, month: 7, year: 4 }[type])
    },
    setInputDate () {
      if (this.lastValue) {
        const array = this.lastValue.split('-')
        this.inputYear = parseInt(array[0], 10)
        this.inputMonth = parseInt(array[1], 10) - 1
        if (this.type === 'date') {
          this.inputDay = parseInt(array[2], 10)
        }
      } else {
        this.inputYear = this.inputYear || this.now.getFullYear()
        this.inputMonth = this.inputMonth == null ? this.inputMonth : this.now.getMonth()
        this.inputDay = this.inputDay || this.now.getDate()
      }
    }
  },

  render () {
    return this.genPicker('v-picker--date')
  }
}
<|endoftext|>


<commit_before>/**
 * Created by a.kopylov on 22.12.2015.
 */
var FacebookStrategy = require('passport-facebook').Strategy;

var User =require('../app/models/user');
var configAuth = require('./auth');

module.exports =function(passport){
    passport.serializeUser(function(user, done){
        done(null,user.id);
    });

    passport.deserializeUser(function(id,done){
        User.findById(id,function(err,user){
            done(err,user);
        });
    });
    passport.use(new FacebookStrategy({
        clientID : configAuth.facebookAuth.clientId,
        clientSecret : configAuth.facebookAuth.clientSecret,
        callbackURL : configAuth.facebookAuth.callbackURL
    },
        function(token, refreshToken, profile, done) {

            // asynchronous
            process.nextTick(function() {

                // find the user in the database based on their facebook id
                User.findOne({ 'facebook.id' : profile.id }, function(err, user) {

                    // if there is an error, stop everything and return that
                    // ie an error connecting to the database
                    if (err)
                        return done(err);

                    // if the user is found, then log them in
                    if (user) {
                        return done(null, user); // user found, return that user
                    } else {
                        // if there is no user found with that facebook id, create them
                        var newUser            = new User();

                        // set all of the facebook information in our user model
                        newUser.facebook.id    = profile.id; // set the users facebook id
                        newUser.facebook.token = token; // we will save the token that facebook provides to the user
                        newUser.facebook.name  = profile.name.givenName + ' ' + profile.name.familyName; // look at the passport user profile to see how names are returned
                        newUser.facebook.email = profile.emails[0].value; // facebook can return multiple emails so we'll take the first

                        // save our user to the database
                        newUser.save(function(err) {
                            if (err)
                                throw err;

                            // if successful, return the new user
                            return done(null, newUser);
                        });
                    }

                });
            });

        }
    ));
};<commit_msg>correction<commit_after>/**
 * Created by a.kopylov on 22.12.2015.
 */
var FacebookStrategy = require('passport-facebook').Strategy;

var User =require('../app/models/user');
var configAuth = require('./auth');

module.exports =function(passport){
    passport.serializeUser(function(user, done){
        done(null,user.id);
    });

    passport.deserializeUser(function(id,done){
        User.findById(id,function(err,user){
            done(err,user);
        });
    });
    passport.use(new FacebookStrategy({
        clientID : configAuth.facebookAuth.clientID,
        clientSecret : configAuth.facebookAuth.clientSecret,
        callbackURL : configAuth.facebookAuth.callbackURL
    },
        function(token, refreshToken, profile, done) {

            // asynchronous
            process.nextTick(function() {

                // find the user in the database based on their facebook id
                User.findOne({ 'facebook.id' : profile.id }, function(err, user) {

                    // if there is an error, stop everything and return that
                    // ie an error connecting to the database
                    if (err)
                        return done(err);

                    // if the user is found, then log them in
                    if (user) {
                        return done(null, user); // user found, return that user
                    } else {
                        // if there is no user found with that facebook id, create them
                        var newUser            = new User();

                        // set all of the facebook information in our user model
                        newUser.facebook.id    = profile.id; // set the users facebook id
                        newUser.facebook.token = token; // we will save the token that facebook provides to the user
                        newUser.facebook.name  = profile.name.givenName + ' ' + profile.name.familyName; // look at the passport user profile to see how names are returned
                        newUser.facebook.email = profile.emails[0].value; // facebook can return multiple emails so we'll take the first

                        // save our user to the database
                        newUser.save(function(err) {
                            if (err)
                                throw err;

                            // if successful, return the new user
                            return done(null, newUser);
                        });
                    }

                });
            });

        }
    ));
};<|endoftext|>


<commit_before>/*!
 * ${copyright}
 */

sap.ui.define(['jquery.sap.global'],
	function(jQuery) {
	"use strict";

	/**
	 * Carousel renderer.
	 * @namespace
	 */
	var CarouselRenderer = {
	};

	/**
	 * Renders the Carousel's HTML, using the provided {@link sap.ui.core.RenderManager}.
	 *
	 * @param {sap.ui.core.RenderManager} oRm the RenderManager that can be used for writing to the render output buffer
	 * @param {sap.ui.core.Control} oControl an object representation of the control that should be rendered
	 */
	CarouselRenderer.render = function(rm, oCarousel){
		//Outer carousel div
		rm.write("<div");
		rm.writeControlData(oCarousel);
		// custom F6 handling
		rm.writeAttribute("data-sap-ui-customfastnavgroup", "true");

		rm.addStyle("width", oCarousel.getWidth());
		rm.addStyle("height", oCarousel.getHeight());
		rm.writeStyles();

		rm.addClass("sapMCrsl");
		//'sapMCrslFluid' is originally from mobify-carousel
		rm.addClass("sapMCrslFluid");

		// add all classes (also custom classes) to carousel tag
		rm.writeClasses();

		var sTooltip = oCarousel.getTooltip_AsString();
		if (sTooltip) {
			rm.writeAttributeEscaped("title", sTooltip);
		}

		rm.writeAttributeEscaped("tabindex","0");

		// ARIA
		rm.writeAccessibilityState(oCarousel, {
			role: "list"
		});

		rm.write(">");

		var aPages = oCarousel.getPages();
		var iPageCount = aPages.length;
		var sPageIndicatorPlacement = oCarousel.getShowPageIndicator() ?
			oCarousel.getPageIndicatorPlacement() : null;

		//visual indicator
		if (sPageIndicatorPlacement === sap.m.PlacementType.Top) {
			this._renderPageIndicator(rm, iPageCount);
		}

		//inner carousel div
		rm.write("
");
		//do housekeeping
		oCarousel._cleanUpScrollContainer();

		var fnRenderPage = function(oPage, iIndex) {
			//item div
			rm.write("
");
				rm.renderControl(oCarousel._createScrollContainer(oPage, iIndex));
			rm.write("
");
		};

		//Render Pages
		aPages.forEach(fnRenderPage);

		rm.write("
");
		//inner div ends

		if (sap.ui.Device.system.desktop && iPageCount > 1) {
			//heads up controls for desktop browsers
			rm.write("
");
				rm.write("
");
				rm.renderControl(oCarousel._getNavigationArrow('left'));
				rm.write("
");

				rm.write("
");
				rm.renderControl(oCarousel._getNavigationArrow('right'));
				rm.write("
");
			rm.write("
");
		}

		//visual indicator
		if (sPageIndicatorPlacement === sap.m.PlacementType.Bottom) {
			this._renderPageIndicator(rm, iPageCount, true);
		}
		rm.write("
");

		//page-wrap ends
	};

	/**
	 * Renders the page indicator, using the provided {@link sap.ui.core.RenderManager}.
	 * Page indicator is only rendered if there is more than one carousel page
	 *
	 * @param {sap.ui.core.RenderManager} oRm the RenderManager that can be used for writing to the render output buffer
	 * @param aPages array of controls to be rendered
	 * @private
	 */
	CarouselRenderer._renderPageIndicator = function(rm, iPageCount, bBottom){
		//page indicator div
		if (iPageCount > 1) {
			rm.write("
");
			for ( var i = 1; i <= iPageCount; i++) {
				//item span
				rm.write("" + i + "");
			}
			rm.write("
");
		}
	};

	return CarouselRenderer;

}, /* bExport= */ true);
<commit_msg>[INERNAL] sap.m.Carousel: tabindex attribute corrected<commit_after>/*!
 * ${copyright}
 */

sap.ui.define(['jquery.sap.global'],
	function(jQuery) {
	"use strict";

	/**
	 * Carousel renderer.
	 * @namespace
	 */
	var CarouselRenderer = {
	};

	/**
	 * Renders the Carousel's HTML, using the provided {@link sap.ui.core.RenderManager}.
	 *
	 * @param {sap.ui.core.RenderManager} oRm the RenderManager that can be used for writing to the render output buffer
	 * @param {sap.ui.core.Control} oControl an object representation of the control that should be rendered
	 */
	CarouselRenderer.render = function(rm, oCarousel){
		//Outer carousel div
		rm.write("<div");
		rm.writeControlData(oCarousel);
		// custom F6 handling
		rm.writeAttribute("data-sap-ui-customfastnavgroup", "true");

		rm.addStyle("width", oCarousel.getWidth());
		rm.addStyle("height", oCarousel.getHeight());
		rm.writeStyles();

		rm.addClass("sapMCrsl");
		//'sapMCrslFluid' is originally from mobify-carousel
		rm.addClass("sapMCrslFluid");

		// add all classes (also custom classes) to carousel tag
		rm.writeClasses();

		var sTooltip = oCarousel.getTooltip_AsString();
		if (sTooltip) {
			rm.writeAttributeEscaped("title", sTooltip);
		}

		rm.writeAttributeEscaped("tabindex","0");

		// ARIA
		rm.writeAccessibilityState(oCarousel, {
			role: "list"
		});

		rm.write(">");

		var aPages = oCarousel.getPages();
		var iPageCount = aPages.length;
		var sPageIndicatorPlacement = oCarousel.getShowPageIndicator() ?
			oCarousel.getPageIndicatorPlacement() : null;

		//visual indicator
		if (sPageIndicatorPlacement === sap.m.PlacementType.Top) {
			this._renderPageIndicator(rm, iPageCount);
		}

		//inner carousel div
		rm.write("
");
		//do housekeeping
		oCarousel._cleanUpScrollContainer();

		var fnRenderPage = function(oPage, iIndex) {
			//item div
			rm.write("
");
				rm.renderControl(oCarousel._createScrollContainer(oPage, iIndex));
			rm.write("
");
		};

		//Render Pages
		aPages.forEach(fnRenderPage);

		rm.write("
");
		//inner div ends

		if (sap.ui.Device.system.desktop && iPageCount > 1) {
			//heads up controls for desktop browsers
			rm.write("
");
				rm.write("
");
				rm.renderControl(oCarousel._getNavigationArrow('left'));
				rm.write("
");

				rm.write("
");
				rm.renderControl(oCarousel._getNavigationArrow('right'));
				rm.write("
");
			rm.write("
");
		}

		//visual indicator
		if (sPageIndicatorPlacement === sap.m.PlacementType.Bottom) {
			this._renderPageIndicator(rm, iPageCount, true);
		}
		rm.write("
");

		//page-wrap ends
	};

	/**
	 * Renders the page indicator, using the provided {@link sap.ui.core.RenderManager}.
	 * Page indicator is only rendered if there is more than one carousel page
	 *
	 * @param {sap.ui.core.RenderManager} oRm the RenderManager that can be used for writing to the render output buffer
	 * @param aPages array of controls to be rendered
	 * @private
	 */
	CarouselRenderer._renderPageIndicator = function(rm, iPageCount, bBottom){
		//page indicator div
		if (iPageCount > 1) {
			rm.write("
");
			for ( var i = 1; i <= iPageCount; i++) {
				//item span
				rm.write("" + i + "");
			}
			rm.write("
");
		}
	};

	return CarouselRenderer;

}, /* bExport= */ true);
<|endoftext|>


<commit_before>/*************************************************************************/
/*  library_godot_eval.js                                                */
/*************************************************************************/
/*                       This file is part of:                           */
/*                           GODOT ENGINE                                */
/*                      https://godotengine.org                          */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   */
/*                                                                       */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the       */
/* "Software"), to deal in the Software without restriction, including   */
/* without limitation the rights to use, copy, modify, merge, publish,   */
/* distribute, sublicense, and/or sell copies of the Software, and to    */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions:                                             */
/*                                                                       */
/* The above copyright notice and this permission notice shall be        */
/* included in all copies or substantial portions of the Software.       */
/*                                                                       */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
/*************************************************************************/

const GodotJSWrapper = {

	$GodotJSWrapper__deps: ['$GodotRuntime', '$IDHandler'],
	$GodotJSWrapper__postset: 'GodotJSWrapper.proxies = new Map();',
	$GodotJSWrapper: {
		proxies: null,
		cb_ret: null,

		MyProxy: function (val) {
			const id = IDHandler.add(this);
			GodotJSWrapper.proxies.set(val, id);
			let refs = 1;
			this.ref = function () {
				refs++;
			};
			this.unref = function () {
				refs--;
				if (refs === 0) {
					IDHandler.remove(id);
					GodotJSWrapper.proxies.delete(val);
				}
			};
			this.get_val = function () {
				return val;
			};
			this.get_id = function () {
				return id;
			};
		},

		get_proxied: function (val) {
			const id = GodotJSWrapper.proxies.get(val);
			if (id === undefined) {
				const proxy = new GodotJSWrapper.MyProxy(val);
				return proxy.get_id();
			}
			IDHandler.get(id).ref();
			return id;
		},

		get_proxied_value: function (id) {
			const proxy = IDHandler.get(id);
			if (proxy === undefined) {
				return undefined;
			}
			return proxy.get_val();
		},

		variant2js: function (type, val) {
			switch (type) {
			case 0:
				return null;
			case 1:
				return !!GodotRuntime.getHeapValue(val, 'i64');
			case 2:
				return GodotRuntime.getHeapValue(val, 'i64');
			case 3:
				return GodotRuntime.getHeapValue(val, 'double');
			case 4:
				return GodotRuntime.parseString(GodotRuntime.getHeapValue(val, '*'));
			case 21: // OBJECT
				return GodotJSWrapper.get_proxied_value(GodotRuntime.getHeapValue(val, 'i64'));
			default:
				return undefined;
			}
		},

		js2variant: function (p_val, p_exchange) {
			if (p_val === undefined || p_val === null) {
				return 0; // NIL
			}
			const type = typeof (p_val);
			if (type === 'boolean') {
				GodotRuntime.setHeapValue(p_exchange, p_val, 'i64');
				return 1; // BOOL
			} else if (type === 'number') {
				if (Number.isInteger(p_val)) {
					GodotRuntime.setHeapValue(p_exchange, p_val, 'i64');
					return 2; // INT
				}
				GodotRuntime.setHeapValue(p_exchange, p_val, 'double');
				return 3; // REAL
			} else if (type === 'string') {
				const c_str = GodotRuntime.allocString(p_val);
				GodotRuntime.setHeapValue(p_exchange, c_str, '*');
				return 4; // STRING
			}
			const id = GodotJSWrapper.get_proxied(p_val);
			GodotRuntime.setHeapValue(p_exchange, id, 'i64');
			return 21;
		},
	},

	godot_js_wrapper_interface_get__sig: 'ii',
	godot_js_wrapper_interface_get: function (p_name) {
		const name = GodotRuntime.parseString(p_name);
		if (typeof (window[name]) !== 'undefined') {
			return GodotJSWrapper.get_proxied(window[name]);
		}
		return 0;
	},

	godot_js_wrapper_object_get__sig: 'iiii',
	godot_js_wrapper_object_get: function (p_id, p_exchange, p_prop) {
		const obj = GodotJSWrapper.get_proxied_value(p_id);
		if (obj === undefined) {
			return 0;
		}
		if (p_prop) {
			const prop = GodotRuntime.parseString(p_prop);
			try {
				return GodotJSWrapper.js2variant(obj[prop], p_exchange);
			} catch (e) {
				GodotRuntime.error(`Error getting variable ${prop} on object`, obj);
				return 0; // NIL
			}
		}
		return GodotJSWrapper.js2variant(obj, p_exchange);
	},

	godot_js_wrapper_object_set__sig: 'viiii',
	godot_js_wrapper_object_set: function (p_id, p_name, p_type, p_exchange) {
		const obj = GodotJSWrapper.get_proxied_value(p_id);
		if (obj === undefined) {
			return;
		}
		const name = GodotRuntime.parseString(p_name);
		try {
			obj[name] = GodotJSWrapper.variant2js(p_type, p_exchange);
		} catch (e) {
			GodotRuntime.error(`Error setting variable ${name} on object`, obj);
		}
	},

	godot_js_wrapper_object_call__sig: 'iiiiiiiii',
	godot_js_wrapper_object_call: function (p_id, p_method, p_args, p_argc, p_convert_callback, p_exchange, p_lock, p_free_lock_callback) {
		const obj = GodotJSWrapper.get_proxied_value(p_id);
		if (obj === undefined) {
			return -1;
		}
		const method = GodotRuntime.parseString(p_method);
		const convert = GodotRuntime.get_func(p_convert_callback);
		const freeLock = GodotRuntime.get_func(p_free_lock_callback);
		const args = new Array(p_argc);
		for (let i = 0; i < p_argc; i++) {
			const type = convert(p_args, i, p_exchange, p_lock);
			const lock = GodotRuntime.getHeapValue(p_lock, '*');
			args[i] = GodotJSWrapper.variant2js(type, p_exchange);
			if (lock) {
				freeLock(p_lock, type);
			}
		}
		try {
			const res = obj[method](...args);
			return GodotJSWrapper.js2variant(res, p_exchange);
		} catch (e) {
			GodotRuntime.error(`Error calling method ${method} on:`, obj, 'error:', e);
			return -1;
		}
	},

	godot_js_wrapper_object_unref__sig: 'vi',
	godot_js_wrapper_object_unref: function (p_id) {
		const proxy = IDHandler.get(p_id);
		if (proxy !== undefined) {
			proxy.unref();
		}
	},

	godot_js_wrapper_create_cb__sig: 'iii',
	godot_js_wrapper_create_cb: function (p_ref, p_func) {
		const func = GodotRuntime.get_func(p_func);
		let id = 0;
		const cb = function () {
			if (!GodotJSWrapper.get_proxied_value(id)) {
				return undefined;
			}
			// The callback will store the returned value in this variable via
			// "godot_js_wrapper_object_set_cb_ret" upon calling the user function.
			// This is safe! JavaScript is single threaded (and using it in threads is not a good idea anyway).
			GodotJSWrapper.cb_ret = null;
			const args = Array.from(arguments);
			func(p_ref, GodotJSWrapper.get_proxied(args), args.length);
			const ret = GodotJSWrapper.cb_ret;
			GodotJSWrapper.cb_ret = null;
			return ret;
		};
		id = GodotJSWrapper.get_proxied(cb);
		return id;
	},

	godot_js_wrapper_object_set_cb_ret__sig: 'vii',
	godot_js_wrapper_object_set_cb_ret: function (p_val_type, p_val_ex) {
		GodotJSWrapper.cb_ret = GodotJSWrapper.variant2js(p_val_type, p_val_ex);
	},

	godot_js_wrapper_object_getvar__sig: 'iiii',
	godot_js_wrapper_object_getvar: function (p_id, p_type, p_exchange) {
		const obj = GodotJSWrapper.get_proxied_value(p_id);
		if (obj === undefined) {
			return -1;
		}
		const prop = GodotJSWrapper.variant2js(p_type, p_exchange);
		if (prop === undefined || prop === null) {
			return -1;
		}
		try {
			return GodotJSWrapper.js2variant(obj[prop], p_exchange);
		} catch (e) {
			GodotRuntime.error(`Error getting variable ${prop} on object`, obj, e);
			return -1;
		}
	},

	godot_js_wrapper_object_setvar__sig: 'iiiiii',
	godot_js_wrapper_object_setvar: function (p_id, p_key_type, p_key_ex, p_val_type, p_val_ex) {
		const obj = GodotJSWrapper.get_proxied_value(p_id);
		if (obj === undefined) {
			return -1;
		}
		const key = GodotJSWrapper.variant2js(p_key_type, p_key_ex);
		try {
			obj[key] = GodotJSWrapper.variant2js(p_val_type, p_val_ex);
			return 0;
		} catch (e) {
			GodotRuntime.error(`Error setting variable ${key} on object`, obj);
			return -1;
		}
	},

	godot_js_wrapper_create_object__sig: 'iiiiiiii',
	godot_js_wrapper_create_object: function (p_object, p_args, p_argc, p_convert_callback, p_exchange, p_lock, p_free_lock_callback) {
		const name = GodotRuntime.parseString(p_object);
		if (typeof (window[name]) === 'undefined') {
			return -1;
		}
		const convert = GodotRuntime.get_func(p_convert_callback);
		const freeLock = GodotRuntime.get_func(p_free_lock_callback);
		const args = new Array(p_argc);
		for (let i = 0; i < p_argc; i++) {
			const type = convert(p_args, i, p_exchange, p_lock);
			const lock = GodotRuntime.getHeapValue(p_lock, '*');
			args[i] = GodotJSWrapper.variant2js(type, p_exchange);
			if (lock) {
				freeLock(p_lock, type);
			}
		}
		try {
			const res = new window[name](...args);
			return GodotJSWrapper.js2variant(res, p_exchange);
		} catch (e) {
			GodotRuntime.error(`Error calling constructor ${name} with args:`, args, 'error:', e);
			return -1;
		}
	},
};

autoAddDeps(GodotJSWrapper, '$GodotJSWrapper');
mergeInto(LibraryManager.library, GodotJSWrapper);

const GodotEval = {
	godot_js_eval__deps: ['$GodotRuntime'],
	godot_js_eval__sig: 'iiiiiii',
	godot_js_eval: function (p_js, p_use_global_ctx, p_union_ptr, p_byte_arr, p_byte_arr_write, p_callback) {
		const js_code = GodotRuntime.parseString(p_js);
		let eval_ret = null;
		try {
			if (p_use_global_ctx) {
				// indirect eval call grants global execution context
				const global_eval = eval; // eslint-disable-line no-eval
				eval_ret = global_eval(js_code);
			} else {
				eval_ret = eval(js_code); // eslint-disable-line no-eval
			}
		} catch (e) {
			GodotRuntime.error(e);
		}

		switch (typeof eval_ret) {
		case 'boolean':
			GodotRuntime.setHeapValue(p_union_ptr, eval_ret, 'i32');
			return 1; // BOOL

		case 'number':
			GodotRuntime.setHeapValue(p_union_ptr, eval_ret, 'double');
			return 3; // REAL

		case 'string':
			GodotRuntime.setHeapValue(p_union_ptr, GodotRuntime.allocString(eval_ret), '*');
			return 4; // STRING

		case 'object':
			if (eval_ret === null) {
				break;
			}

			if (ArrayBuffer.isView(eval_ret) && !(eval_ret instanceof Uint8Array)) {
				eval_ret = new Uint8Array(eval_ret.buffer);
			} else if (eval_ret instanceof ArrayBuffer) {
				eval_ret = new Uint8Array(eval_ret);
			}
			if (eval_ret instanceof Uint8Array) {
				const func = GodotRuntime.get_func(p_callback);
				const bytes_ptr = func(p_byte_arr, p_byte_arr_write, eval_ret.length);
				HEAPU8.set(eval_ret, bytes_ptr);
				return 20; // POOL_BYTE_ARRAY
			}
			break;

			// no default
		}
		return 0; // NIL
	},
};

mergeInto(LibraryManager.library, GodotEval);
<commit_msg>Fix Object type in GodotJSWrapper.<commit_after>/*************************************************************************/
/*  library_godot_eval.js                                                */
/*************************************************************************/
/*                       This file is part of:                           */
/*                           GODOT ENGINE                                */
/*                      https://godotengine.org                          */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   */
/*                                                                       */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the       */
/* "Software"), to deal in the Software without restriction, including   */
/* without limitation the rights to use, copy, modify, merge, publish,   */
/* distribute, sublicense, and/or sell copies of the Software, and to    */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions:                                             */
/*                                                                       */
/* The above copyright notice and this permission notice shall be        */
/* included in all copies or substantial portions of the Software.       */
/*                                                                       */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
/*************************************************************************/

const GodotJSWrapper = {

	$GodotJSWrapper__deps: ['$GodotRuntime', '$IDHandler'],
	$GodotJSWrapper__postset: 'GodotJSWrapper.proxies = new Map();',
	$GodotJSWrapper: {
		proxies: null,
		cb_ret: null,

		MyProxy: function (val) {
			const id = IDHandler.add(this);
			GodotJSWrapper.proxies.set(val, id);
			let refs = 1;
			this.ref = function () {
				refs++;
			};
			this.unref = function () {
				refs--;
				if (refs === 0) {
					IDHandler.remove(id);
					GodotJSWrapper.proxies.delete(val);
				}
			};
			this.get_val = function () {
				return val;
			};
			this.get_id = function () {
				return id;
			};
		},

		get_proxied: function (val) {
			const id = GodotJSWrapper.proxies.get(val);
			if (id === undefined) {
				const proxy = new GodotJSWrapper.MyProxy(val);
				return proxy.get_id();
			}
			IDHandler.get(id).ref();
			return id;
		},

		get_proxied_value: function (id) {
			const proxy = IDHandler.get(id);
			if (proxy === undefined) {
				return undefined;
			}
			return proxy.get_val();
		},

		variant2js: function (type, val) {
			switch (type) {
			case 0:
				return null;
			case 1:
				return !!GodotRuntime.getHeapValue(val, 'i64');
			case 2:
				return GodotRuntime.getHeapValue(val, 'i64');
			case 3:
				return GodotRuntime.getHeapValue(val, 'double');
			case 4:
				return GodotRuntime.parseString(GodotRuntime.getHeapValue(val, '*'));
			case 24: // OBJECT
				return GodotJSWrapper.get_proxied_value(GodotRuntime.getHeapValue(val, 'i64'));
			default:
				return undefined;
			}
		},

		js2variant: function (p_val, p_exchange) {
			if (p_val === undefined || p_val === null) {
				return 0; // NIL
			}
			const type = typeof (p_val);
			if (type === 'boolean') {
				GodotRuntime.setHeapValue(p_exchange, p_val, 'i64');
				return 1; // BOOL
			} else if (type === 'number') {
				if (Number.isInteger(p_val)) {
					GodotRuntime.setHeapValue(p_exchange, p_val, 'i64');
					return 2; // INT
				}
				GodotRuntime.setHeapValue(p_exchange, p_val, 'double');
				return 3; // REAL
			} else if (type === 'string') {
				const c_str = GodotRuntime.allocString(p_val);
				GodotRuntime.setHeapValue(p_exchange, c_str, '*');
				return 4; // STRING
			}
			const id = GodotJSWrapper.get_proxied(p_val);
			GodotRuntime.setHeapValue(p_exchange, id, 'i64');
			return 24; // OBJECT
		},
	},

	godot_js_wrapper_interface_get__sig: 'ii',
	godot_js_wrapper_interface_get: function (p_name) {
		const name = GodotRuntime.parseString(p_name);
		if (typeof (window[name]) !== 'undefined') {
			return GodotJSWrapper.get_proxied(window[name]);
		}
		return 0;
	},

	godot_js_wrapper_object_get__sig: 'iiii',
	godot_js_wrapper_object_get: function (p_id, p_exchange, p_prop) {
		const obj = GodotJSWrapper.get_proxied_value(p_id);
		if (obj === undefined) {
			return 0;
		}
		if (p_prop) {
			const prop = GodotRuntime.parseString(p_prop);
			try {
				return GodotJSWrapper.js2variant(obj[prop], p_exchange);
			} catch (e) {
				GodotRuntime.error(`Error getting variable ${prop} on object`, obj);
				return 0; // NIL
			}
		}
		return GodotJSWrapper.js2variant(obj, p_exchange);
	},

	godot_js_wrapper_object_set__sig: 'viiii',
	godot_js_wrapper_object_set: function (p_id, p_name, p_type, p_exchange) {
		const obj = GodotJSWrapper.get_proxied_value(p_id);
		if (obj === undefined) {
			return;
		}
		const name = GodotRuntime.parseString(p_name);
		try {
			obj[name] = GodotJSWrapper.variant2js(p_type, p_exchange);
		} catch (e) {
			GodotRuntime.error(`Error setting variable ${name} on object`, obj);
		}
	},

	godot_js_wrapper_object_call__sig: 'iiiiiiiii',
	godot_js_wrapper_object_call: function (p_id, p_method, p_args, p_argc, p_convert_callback, p_exchange, p_lock, p_free_lock_callback) {
		const obj = GodotJSWrapper.get_proxied_value(p_id);
		if (obj === undefined) {
			return -1;
		}
		const method = GodotRuntime.parseString(p_method);
		const convert = GodotRuntime.get_func(p_convert_callback);
		const freeLock = GodotRuntime.get_func(p_free_lock_callback);
		const args = new Array(p_argc);
		for (let i = 0; i < p_argc; i++) {
			const type = convert(p_args, i, p_exchange, p_lock);
			const lock = GodotRuntime.getHeapValue(p_lock, '*');
			args[i] = GodotJSWrapper.variant2js(type, p_exchange);
			if (lock) {
				freeLock(p_lock, type);
			}
		}
		try {
			const res = obj[method](...args);
			return GodotJSWrapper.js2variant(res, p_exchange);
		} catch (e) {
			GodotRuntime.error(`Error calling method ${method} on:`, obj, 'error:', e);
			return -1;
		}
	},

	godot_js_wrapper_object_unref__sig: 'vi',
	godot_js_wrapper_object_unref: function (p_id) {
		const proxy = IDHandler.get(p_id);
		if (proxy !== undefined) {
			proxy.unref();
		}
	},

	godot_js_wrapper_create_cb__sig: 'iii',
	godot_js_wrapper_create_cb: function (p_ref, p_func) {
		const func = GodotRuntime.get_func(p_func);
		let id = 0;
		const cb = function () {
			if (!GodotJSWrapper.get_proxied_value(id)) {
				return undefined;
			}
			// The callback will store the returned value in this variable via
			// "godot_js_wrapper_object_set_cb_ret" upon calling the user function.
			// This is safe! JavaScript is single threaded (and using it in threads is not a good idea anyway).
			GodotJSWrapper.cb_ret = null;
			const args = Array.from(arguments);
			func(p_ref, GodotJSWrapper.get_proxied(args), args.length);
			const ret = GodotJSWrapper.cb_ret;
			GodotJSWrapper.cb_ret = null;
			return ret;
		};
		id = GodotJSWrapper.get_proxied(cb);
		return id;
	},

	godot_js_wrapper_object_set_cb_ret__sig: 'vii',
	godot_js_wrapper_object_set_cb_ret: function (p_val_type, p_val_ex) {
		GodotJSWrapper.cb_ret = GodotJSWrapper.variant2js(p_val_type, p_val_ex);
	},

	godot_js_wrapper_object_getvar__sig: 'iiii',
	godot_js_wrapper_object_getvar: function (p_id, p_type, p_exchange) {
		const obj = GodotJSWrapper.get_proxied_value(p_id);
		if (obj === undefined) {
			return -1;
		}
		const prop = GodotJSWrapper.variant2js(p_type, p_exchange);
		if (prop === undefined || prop === null) {
			return -1;
		}
		try {
			return GodotJSWrapper.js2variant(obj[prop], p_exchange);
		} catch (e) {
			GodotRuntime.error(`Error getting variable ${prop} on object`, obj, e);
			return -1;
		}
	},

	godot_js_wrapper_object_setvar__sig: 'iiiiii',
	godot_js_wrapper_object_setvar: function (p_id, p_key_type, p_key_ex, p_val_type, p_val_ex) {
		const obj = GodotJSWrapper.get_proxied_value(p_id);
		if (obj === undefined) {
			return -1;
		}
		const key = GodotJSWrapper.variant2js(p_key_type, p_key_ex);
		try {
			obj[key] = GodotJSWrapper.variant2js(p_val_type, p_val_ex);
			return 0;
		} catch (e) {
			GodotRuntime.error(`Error setting variable ${key} on object`, obj);
			return -1;
		}
	},

	godot_js_wrapper_create_object__sig: 'iiiiiiii',
	godot_js_wrapper_create_object: function (p_object, p_args, p_argc, p_convert_callback, p_exchange, p_lock, p_free_lock_callback) {
		const name = GodotRuntime.parseString(p_object);
		if (typeof (window[name]) === 'undefined') {
			return -1;
		}
		const convert = GodotRuntime.get_func(p_convert_callback);
		const freeLock = GodotRuntime.get_func(p_free_lock_callback);
		const args = new Array(p_argc);
		for (let i = 0; i < p_argc; i++) {
			const type = convert(p_args, i, p_exchange, p_lock);
			const lock = GodotRuntime.getHeapValue(p_lock, '*');
			args[i] = GodotJSWrapper.variant2js(type, p_exchange);
			if (lock) {
				freeLock(p_lock, type);
			}
		}
		try {
			const res = new window[name](...args);
			return GodotJSWrapper.js2variant(res, p_exchange);
		} catch (e) {
			GodotRuntime.error(`Error calling constructor ${name} with args:`, args, 'error:', e);
			return -1;
		}
	},
};

autoAddDeps(GodotJSWrapper, '$GodotJSWrapper');
mergeInto(LibraryManager.library, GodotJSWrapper);

const GodotEval = {
	godot_js_eval__deps: ['$GodotRuntime'],
	godot_js_eval__sig: 'iiiiiii',
	godot_js_eval: function (p_js, p_use_global_ctx, p_union_ptr, p_byte_arr, p_byte_arr_write, p_callback) {
		const js_code = GodotRuntime.parseString(p_js);
		let eval_ret = null;
		try {
			if (p_use_global_ctx) {
				// indirect eval call grants global execution context
				const global_eval = eval; // eslint-disable-line no-eval
				eval_ret = global_eval(js_code);
			} else {
				eval_ret = eval(js_code); // eslint-disable-line no-eval
			}
		} catch (e) {
			GodotRuntime.error(e);
		}

		switch (typeof eval_ret) {
		case 'boolean':
			GodotRuntime.setHeapValue(p_union_ptr, eval_ret, 'i32');
			return 1; // BOOL

		case 'number':
			GodotRuntime.setHeapValue(p_union_ptr, eval_ret, 'double');
			return 3; // REAL

		case 'string':
			GodotRuntime.setHeapValue(p_union_ptr, GodotRuntime.allocString(eval_ret), '*');
			return 4; // STRING

		case 'object':
			if (eval_ret === null) {
				break;
			}

			if (ArrayBuffer.isView(eval_ret) && !(eval_ret instanceof Uint8Array)) {
				eval_ret = new Uint8Array(eval_ret.buffer);
			} else if (eval_ret instanceof ArrayBuffer) {
				eval_ret = new Uint8Array(eval_ret);
			}
			if (eval_ret instanceof Uint8Array) {
				const func = GodotRuntime.get_func(p_callback);
				const bytes_ptr = func(p_byte_arr, p_byte_arr_write, eval_ret.length);
				HEAPU8.set(eval_ret, bytes_ptr);
				return 20; // POOL_BYTE_ARRAY
			}
			break;

			// no default
		}
		return 0; // NIL
	},
};

mergeInto(LibraryManager.library, GodotEval);
<|endoftext|>


<commit_before>import config from 'config';
import { permanentRootCookieOptions } from 'server/initialState/permanentRootCookieOptions';
import { SEPERATOR, VERSION } from './constants';

export default (ctx, session) => {
  // Set the token cookie to be on the root reddit domain if we're not
  // running on localhost
  const options = permanentRootCookieOptions(ctx);

  ctx.cookies.set(
    'token',
    `${session.tokenString}${SEPERATOR}${VERSION}`,
    options
  );
};
<commit_msg>Fix lint error<commit_after>import { permanentRootCookieOptions } from 'server/initialState/permanentRootCookieOptions';
import { SEPERATOR, VERSION } from './constants';

export default (ctx, session) => {
  // Set the token cookie to be on the root reddit domain if we're not
  // running on localhost
  const options = permanentRootCookieOptions(ctx);

  ctx.cookies.set(
    'token',
    `${session.tokenString}${SEPERATOR}${VERSION}`,
    options
  );
};
<|endoftext|>