<commit_before>"use strict";
define(["p5", "app/ts/inequality/Inequality.ts", "../../../lib/equation_editor/test_cases.js", "/partials/equation_editor/equation_editor.html"], function (p5, MySketch, tester, templateUrl) {

    MySketch = MySketch.MySketch;

    return ["$timeout", "$rootScope", "api", "$stateParams", "equationEditor", function ($timeout, $rootScope, api, $stateParams, equationEditor) {

        return {
            scope: true,
            restrict: "A",
            templateUrl: templateUrl,
            link: function (scope, element, _attrs) {


                /*** Lifecycle and buttons ***/


                // The DOM element that holds the menus and the canvas.
                scope.equationEditorElement = element;

                // Prevent default event handling on the canvas.
                element.on("touchstart touchmove touchended", "canvas", function (e) {
                    e.preventDefault();
                });

                // This holds the p5 sketch, the actual equation editor.
                let sketch = null;

                // Are we dragging a new symbol from the menu?
                scope.draggingNewSymbol = false;

                // The moving symbol(s) when symbol(s) are moving.
                // In practice, only one (top-level) symbol can be moving at any given time, because no multi-touch.
                scope.selectedSymbols = [];

                // TODO Figure out this one. I'm not sure this is necessary, really...
                scope.selectionHandleFlags = {
                    showCalc: false,
                    showResize: true,
                    showMove: false
                };

                scope.historyPtr = -1;
                scope.history = [];

                // Adds a checkpoint to the history, so we can undo and redo.
                scope.$on("historyCheckpoint", function () {
                    let newEntry = JSON.stringify(scope.state);
                    let currentEntry = JSON.stringify(scope.history[scope.historyPtr]);

                    if (newEntry !== currentEntry) {
                        scope.historyPtr++;
                        scope.history.splice(scope.historyPtr, scope.history.length - scope.historyPtr, JSON.parse(newEntry));

                        // console.log("historyCheckpoint:", scope.history);
                    }
                });

                scope.undo = function () {
                    if (scope.historyPtr > 0) {
                        scope.historyPtr--;

                        let e = scope.history[scope.historyPtr];
                        scope.state = JSON.parse(JSON.stringify(e));
                        sketch.symbols = [];
                        for (let i in scope.state.symbols) {
                            sketch.parseSubtreeObject(scope.state.symbols[i]);
                        }
                        scope.log.actions.push({
                            event: "UNDO",
                            timestamp: Date.now()
                        });

                    }
                };

                scope.redo = function () {
                    if (scope.historyPtr < scope.history.length - 1) {
                        scope.historyPtr++;

                        let e = scope.history[scope.historyPtr];
                        scope.state = JSON.parse(JSON.stringify(e));
                        sketch.symbols = [];
                        for (let i in scope.state.symbols) {
                            sketch.parseSubtreeObject(scope.state.symbols[i]);
                        }
                        scope.log.actions.push({
                            event: "REDO",
                            timestamp: Date.now()
                        });
                    }
                };

                // ? This seems to be unnecessary now.
                scope.trash = function () {
                    scope.$emit("historyCheckpoint");
                };

                // Closes the editor and returns to the question screen with a potential answer.
                scope.submit = function () {
                    $("#equationModal").foundation("reveal", "close");
                };

                // Centres all the objects in the canvas.
                scope.centre = function () {
                    sketch.centre();
                };

                scope.newEditorState = function (s) {
                    scope.state = s;
                    scope.state.textEntry = false;

                    console.log("New state:", s);

                    let rp = $(".result-preview > span");

                    rp.empty();

                    // this renders the result in the preview box in the bottom right corner of the eqn editor
                    if (scope.state.result) {
                        scope.state.result["uniqueSymbols"] = replaceSpecialChars(scope.state.result["uniqueSymbols"]).replace(/\\/g, "");
                        // Sort them into a unique order:
                        scope.state.result["uniqueSymbols"] = scope.state.result["uniqueSymbols"].split(", ").sort(uniqueSymbolsSortFn).join(", ");
                        scope.state.result["uniqueSymbols"] = scope.state.result["uniqueSymbols"].replace(/varepsilon/g, "epsilon");

                        scope.state.result["tex"] = replaceSpecialChars(scope.state.result["tex"]);
                        scope.state.result["python"] = replaceSpecialChars(scope.state.result["python"]).replace(/\\/g, "").replace(/varepsilon/g, "epsilon");
                        katex.render(scope.state.result["tex"], rp[0]);
                    }

                    let w = 0;
                    if (scope.state.result) {
                        let spans = rp.find(".katex > span.katex-html > span");
                        w = spans.map((i, e) => $(e).width()).toArray().reduce((a, c) => a + c);
                    }
                    let resultPreview = $(".result-preview");
                    resultPreview.stop(true);
                    resultPreview.animate({
                        width: w + $(".equation-editor > .hex-button.submit").width()
                    }, 200);

                    scope.$emit("historyCheckpoint");
                };

                // Handles key commands.
                // Some of these may be removed (like the trash one). Some are still useful, like the test cases.
                element.on("keydown", function (e) {
                    let test_cases_lib = ($stateParams.mode === 'chemistry') ? tester.testCasesChemistry : tester.testCasesMaths;
                    if ($stateParams.testing) {
                        console.log("KeyDown", e.which || e.keyCode);
                        switch (e.which || e.keyCode) {
                            case 8: // Backspace. Deliberately fall through.
                            case 46: // Delete
                                e.stopPropagation();
                                e.preventDefault();
                                scope.trash();
                                scope.$apply();
                                break;<commit_msg>:bug: Provide initial value to reduce on potentially empty array.<commit_after>"use strict";
define(["p5", "app/ts/inequality/Inequality.ts", "../../../lib/equation_editor/test_cases.js", "/partials/equation_editor/equation_editor.html"], function (p5, MySketch, tester, templateUrl) {

    MySketch = MySketch.MySketch;

    return ["$timeout", "$rootScope", "api", "$stateParams", "equationEditor", function ($timeout, $rootScope, api, $stateParams, equationEditor) {

        return {
            scope: true,
            restrict: "A",
            templateUrl: templateUrl,
            link: function (scope, element, _attrs) {


                /*** Lifecycle and buttons ***/


                // The DOM element that holds the menus and the canvas.
                scope.equationEditorElement = element;

                // Prevent default event handling on the canvas.
                element.on("touchstart touchmove touchended", "canvas", function (e) {
                    e.preventDefault();
                });

                // This holds the p5 sketch, the actual equation editor.
                let sketch = null;

                // Are we dragging a new symbol from the menu?
                scope.draggingNewSymbol = false;

                // The moving symbol(s) when symbol(s) are moving.
                // In practice, only one (top-level) symbol can be moving at any given time, because no multi-touch.
                scope.selectedSymbols = [];

                // TODO Figure out this one. I'm not sure this is necessary, really...
                scope.selectionHandleFlags = {
                    showCalc: false,
                    showResize: true,
                    showMove: false
                };

                scope.historyPtr = -1;
                scope.history = [];

                // Adds a checkpoint to the history, so we can undo and redo.
                scope.$on("historyCheckpoint", function () {
                    let newEntry = JSON.stringify(scope.state);
                    let currentEntry = JSON.stringify(scope.history[scope.historyPtr]);

                    if (newEntry !== currentEntry) {
                        scope.historyPtr++;
                        scope.history.splice(scope.historyPtr, scope.history.length - scope.historyPtr, JSON.parse(newEntry));

                        // console.log("historyCheckpoint:", scope.history);
                    }
                });

                scope.undo = function () {
                    if (scope.historyPtr > 0) {
                        scope.historyPtr--;

                        let e = scope.history[scope.historyPtr];
                        scope.state = JSON.parse(JSON.stringify(e));
                        sketch.symbols = [];
                        for (let i in scope.state.symbols) {
                            sketch.parseSubtreeObject(scope.state.symbols[i]);
                        }
                        scope.log.actions.push({
                            event: "UNDO",
                            timestamp: Date.now()
                        });

                    }
                };

                scope.redo = function () {
                    if (scope.historyPtr < scope.history.length - 1) {
                        scope.historyPtr++;

                        let e = scope.history[scope.historyPtr];
                        scope.state = JSON.parse(JSON.stringify(e));
                        sketch.symbols = [];
                        for (let i in scope.state.symbols) {
                            sketch.parseSubtreeObject(scope.state.symbols[i]);
                        }
                        scope.log.actions.push({
                            event: "REDO",
                            timestamp: Date.now()
                        });
                    }
                };

                // ? This seems to be unnecessary now.
                scope.trash = function () {
                    scope.$emit("historyCheckpoint");
                };

                // Closes the editor and returns to the question screen with a potential answer.
                scope.submit = function () {
                    $("#equationModal").foundation("reveal", "close");
                };

                // Centres all the objects in the canvas.
                scope.centre = function () {
                    sketch.centre();
                };

                scope.newEditorState = function (s) {
                    scope.state = s;
                    scope.state.textEntry = false;

                    console.log("New state:", s);

                    let rp = $(".result-preview > span");

                    rp.empty();

                    // this renders the result in the preview box in the bottom right corner of the eqn editor
                    if (scope.state.result) {
                        scope.state.result["uniqueSymbols"] = replaceSpecialChars(scope.state.result["uniqueSymbols"]).replace(/\\/g, "");
                        // Sort them into a unique order:
                        scope.state.result["uniqueSymbols"] = scope.state.result["uniqueSymbols"].split(", ").sort(uniqueSymbolsSortFn).join(", ");
                        scope.state.result["uniqueSymbols"] = scope.state.result["uniqueSymbols"].replace(/varepsilon/g, "epsilon");

                        scope.state.result["tex"] = replaceSpecialChars(scope.state.result["tex"]);
                        scope.state.result["python"] = replaceSpecialChars(scope.state.result["python"]).replace(/\\/g, "").replace(/varepsilon/g, "epsilon");
                        katex.render(scope.state.result["tex"], rp[0]);
                    }

                    let w = 0;
                    if (scope.state.result) {
                        let spans = rp.find(".katex > span.katex-html > span");
                        w = spans.map((i, e) => $(e).width()).toArray().reduce((a, c) => a + c, 0);
                    }
                    let resultPreview = $(".result-preview");
                    resultPreview.stop(true);
                    resultPreview.animate({
                        width: w + $(".equation-editor > .hex-button.submit").width()
                    }, 200);

                    scope.$emit("historyCheckpoint");
                };

                // Handles key commands.
                // Some of these may be removed (like the trash one). Some are still useful, like the test cases.
                element.on("keydown", function (e) {
                    let test_cases_lib = ($stateParams.mode === 'chemistry') ? tester.testCasesChemistry : tester.testCasesMaths;
                    if ($stateParams.testing) {
                        console.log("KeyDown", e.which || e.keyCode);
                        switch (e.which || e.keyCode) {
                            case 8: // Backspace. Deliberately fall through.
                            case 46: // Delete
                                e.stopPropagation();
                                e.preventDefault();
                                scope.trash();
                                scope.$apply();
                                break;
{'fraction_non_alphanumeric': 0.1133337980065519, 'fraction_numerical': 0.0020213285007318602, 'mean_word_length': 1.1972434915773353, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '823544', 'n_tokens_mistral': 3507, 'n_tokens_neox': 3192, 'n_words': 777}